X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FCirculation.pm;h=48b7b4a1d539773b484fc3669a66ce99fccaf3a1;hb=374b6f4b9f33a776d04cdaa696b40e8e033dda32;hp=96ae0d963fb9d899ce0d53c8cf20f41b421c88e9;hpb=bb4ab3ee765e5664f2d1645efd4b5e5e973a9d56;p=koha_fer diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 96ae0d963f..48b7b4a1d5 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -38,11 +38,21 @@ use C4::Branch; # GetBranches use C4::Log; # logaction use C4::Koha qw(GetAuthorisedValueByCode); use C4::Overdues qw(CalcFine UpdateFine); +use Algorithm::CheckDigits; + use Data::Dumper; use Koha::DateUtils; use Koha::Calendar; use Carp; - +use Date::Calc qw( + Today + Today_and_Now + Add_Delta_YM + Add_Delta_DHMS + Date_to_Days + Day_of_Week + Add_Delta_Days +); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); BEGIN { @@ -169,6 +179,14 @@ sub barcodedecode { $barcode =~ s/^(\D+)[0]*(\d+)$/$branch-$1-$2/i; } } + } 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 = '0' x ( 13 - length($barcode) ) . $barcode; + } else { + warn "# [$barcode] not valid EAN-13/UPC-A\n"; + } } return $barcode; # return barcode, modified or not } @@ -701,7 +719,7 @@ sub CanBookBeIssued { } if ($duedate) { my $today = $now->clone(); - $today->truncate( to => 'minutes'); + $today->truncate( to => 'minute'); if (DateTime->compare($duedate,$today) == -1 ) { # duedate cannot be before now $needsconfirmation{INVALID_DATE} = output_pref($duedate); } @@ -738,8 +756,8 @@ sub CanBookBeIssued { day => $d, time_zone => C4::Context->tz, ); - $expiry_dt->truncate( to => 'days'); - my $today = $now->clone()->truncate(to => 'days'); + $expiry_dt->truncate( to => 'day'); + my $today = $now->clone()->truncate(to => 'day'); if (DateTime->compare($today, $expiry_dt) == 1) { $issuingimpossible{EXPIRED} = 1; } @@ -931,6 +949,62 @@ sub CanBookBeIssued { } } } + # + # CHECK AGE RESTRICTION + # + + # 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)) + { + # 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; + for my $value (@values) { + $index ++; + for my $marker (@markers) { + $marker =~ s/^\s+//; #remove leading spaces + $marker =~ s/\s+$//; #remove trailing spaces + if (uc($marker) eq uc($value)) { + $take = $index; + last; + } + } + if ($take > -1) { + last; + } + } + # Index points to the next value + my $restrictionyear = 0; + if (($take <= $#values) && ($take >= 0)){ + $restrictionyear += @values[$take]; + } + + 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)) { + @alloweddate[2] = 28; + } + + if ( Date_to_Days(Today) < Date_to_Days(@alloweddate) -1 ) { + if (C4::Context->preference('AgeRestrictionOverride' )) { + $needsconfirmation{AGE_RESTRICTION} = "$bibvalues"; + } + else { + $issuingimpossible{AGE_RESTRICTION} = "$bibvalues"; + } + } + } + } + } return ( \%issuingimpossible, \%needsconfirmation, \%alerts ); } @@ -1051,7 +1125,7 @@ sub AddIssue { $datedue = CalcDateDue( $issuedate, $itype, $branch, $borrower ); } - $datedue->truncate( to => 'minutes'); + $datedue->truncate( to => 'minute'); $sth->execute( $borrower->{'borrowernumber'}, # borrowernumber $item->{'itemnumber'}, # itemnumber @@ -1063,6 +1137,9 @@ sub AddIssue { CartToShelf( $item->{'itemnumber'} ); } $item->{'issues'}++; + if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) { + UpdateTotalIssues($item->{'biblionumber'}, 1); + } ## If item was lost, it has now been found, reverse any list item charges if neccessary. if ( $item->{'itemlost'} ) { @@ -1199,53 +1276,16 @@ Get the Hard Due Date and it's comparison for an itemtype, a borrower type and a sub GetHardDueDate { my ( $borrowertype, $itemtype, $branchcode ) = @_; - my $dbh = C4::Context->dbh; - my $sth = - $dbh->prepare( -"select hardduedate, hardduedatecompare from issuingrules where categorycode=? and itemtype=? and branchcode=?" - ); - $sth->execute( $borrowertype, $itemtype, $branchcode ); - my $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - $sth->execute( $borrowertype, "*", $branchcode ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - $sth->execute( "*", $itemtype, $branchcode ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - $sth->execute( "*", "*", $branchcode ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - $sth->execute( $borrowertype, $itemtype, "*" ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - $sth->execute( $borrowertype, "*", "*" ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - $sth->execute( "*", $itemtype, "*" ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; + my $rule = GetIssuingRule( $borrowertype, $itemtype, $branchcode ); - $sth->execute( "*", "*", "*" ); - $results = $sth->fetchrow_hashref; - return (dt_from_string($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) - if defined($results) && $results->{hardduedate}; - - # if no rule is set => return undefined - return (undef, undef); + if ( defined( $rule ) ) { + if ( $rule->{hardduedate} ) { + return (dt_from_string($rule->{hardduedate}, 'iso'),$rule->{hardduedatecompare}); + } else { + return (undef, undef); + } + } } =head2 GetIssuingRule @@ -1437,7 +1477,8 @@ sub GetBranchItemRule { foreach my $attempt (@attempts) { my ($query, @bind_params) = @{$attempt}; - my $search_result = $dbh->selectrow_hashref ( $query , {}, @bind_params ); + 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 @@ -1603,8 +1644,8 @@ sub AddReturn { } # case of a return of document (deal with issues and holdingbranch) - if ($doreturn) { my $today = DateTime->now( time_zone => C4::Context->tz() ); + if ($doreturn) { my $datedue = $issue->{date_due}; $borrower or warn "AddReturn without current borrower"; my $circControlBranch; @@ -1614,13 +1655,12 @@ sub AddReturn { # FIXME: check issuedate > returndate, factoring in holidays #$circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );; $circControlBranch = _GetCircControlBranch($item,$borrower); - my $datedue = $issue->{date_due}; $issue->{'overdue'} = DateTime->compare($issue->{'date_due'}, $today ) == -1 ? 1 : 0; } if ($borrowernumber) { if($issue->{'overdue'}){ - my ( $amount, $type, $daycounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today ); + my ( $amount, $type, $unitcounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today ); $type ||= q{}; if ( $amount > 0 && ( C4::Context->preference('finesMode') eq 'production' )) { C4::Overdues::UpdateFine( @@ -1656,12 +1696,15 @@ sub AddReturn { ); $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 { $messages->{'WrongTransfer'} = $tobranch; $messages->{'WrongTransferItem'} = $item->{'itemnumber'}; } $validTransfert = 1; + } else { + ShelfToCart( $item->{'itemnumber'} ) if ( C4::Context->preference("ReturnToShelvingCart") ); } # fix up the accounts..... @@ -1675,9 +1718,12 @@ sub AddReturn { my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox); defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!"; # zero is OK, check defined - # fix fine days - my $debardate = _FixFineDaysOnReturn( $borrower, $item, $issue->{date_due} ); - $messages->{'Debarred'} = $debardate if ($debardate); + if ( $issue->{overdue} && $issue->{date_due} ) { +# fix fine days + my $debardate = + _debar_user_on_return( $borrower, $item, $issue->{date_due}, $today ); + $messages->{Debarred} = $debardate if ($debardate); + } } # find reserves..... @@ -1802,26 +1848,27 @@ sub MarkIssueReturned { $sth_del->execute($borrowernumber, $itemnumber); } -=head2 _FixFineDaysOnReturn +=head2 _debar_user_on_return - &_FixFineDaysOnReturn($borrower, $item, $datedue); + _debar_user_on_return($borrower, $item, $datedue, today); C<$borrower> borrower hashref C<$item> item hashref -C<$datedue> date due +C<$datedue> date due DateTime object + +C<$today> DateTime object representing the return time + +Internal function, called only by AddReturn that calculates and updates + the user fine days, and debars him if necessary. -Internal function, called only by AddReturn that calculate and update the user fine days, and debars him +Should only be called for overdue returns =cut -sub _FixFineDaysOnReturn { - my ( $borrower, $item, $datedue ) = @_; - return unless ($datedue); - - my $dt_due = dt_from_string( $datedue ); - my $dt_today = DateTime->now( time_zone => C4::Context->tz() ); +sub _debar_user_on_return { + my ( $borrower, $item, $dt_due, $dt_today ) = @_; my $branchcode = _GetCircControlBranch( $item, $borrower ); my $calendar = Koha::Calendar->new( branchcode => $branchcode ); @@ -1830,35 +1877,41 @@ sub _FixFineDaysOnReturn { my $deltadays = $calendar->days_between( $dt_due, $dt_today ); my $circcontrol = C4::Context::preference('CircControl'); - my $issuingrule = GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode ); - my $finedays = $issuingrule->{finedays}; - my $unit = $issuingrule->{lengthunit}; - - # exit if no finedays defined - return unless $finedays; - # finedays is in days, so hourly loans must multiply by 24 - # thus 1 hour late equals 1 day suspension * finedays rate - $finedays = $finedays * 24 if ($unit eq 'hours'); - - # grace period is measured in the same units as the loan - my $grace = DateTime::Duration->new( $unit => $issuingrule->{firstremind} ); - - if ( ( $deltadays - $grace )->is_positive ) { # you can't compare DateTime::Durations with logical operators - my $new_debar_dt = $dt_today->clone()->add_duration( $deltadays * $finedays ); - my $borrower_debar_dt = dt_from_string( $borrower->{debarred} ); - # check to see if the current debar date is a valid date - if ( $borrower->{debarred} && $borrower_debar_dt ) { - # if so, is it before the new date? update only if true - if ( DateTime->compare( $borrower_debar_dt, $new_debar_dt ) == -1 ) { - C4::Members::DebarMember( $borrower->{borrowernumber}, $new_debar_dt->ymd() ); - return $new_debar_dt->ymd(); + my $issuingrule = + GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode ); + my $finedays = $issuingrule->{finedays}; + my $unit = $issuingrule->{lengthunit}; + + if ($finedays) { + + # finedays is in days, so hourly loans must multiply by 24 + # thus 1 hour late equals 1 day suspension * finedays rate + $finedays = $finedays * 24 if ( $unit eq 'hours' ); + + # grace period is measured in the same units as the loan + my $grace = + DateTime::Duration->new( $unit => $issuingrule->{firstremind} ); + if ( $deltadays->subtract($grace)->is_positive() ) { + + my $new_debar_dt = + $dt_today->clone()->add_duration( $deltadays * $finedays ); + if ( $borrower->{debarred} ) { + my $borrower_debar_dt = dt_from_string( $borrower->{debarred} ); + + # Update patron only if new date > old + if ( DateTime->compare( $borrower_debar_dt, $new_debar_dt ) != + -1 ) + { + return; + } + } - # if the borrower's debar date is not set or valid, debar them - } else { - C4::Members::DebarMember( $borrower->{borrowernumber}, $new_debar_dt->ymd() ); + C4::Members::DebarMember( $borrower->{borrowernumber}, + $new_debar_dt->ymd() ); return $new_debar_dt->ymd(); } } + return; } =head2 _FixOverduesOnReturn @@ -2081,10 +2134,10 @@ sub GetItemIssue { my $data = $sth->fetchrow_hashref; return unless $data; $data->{issuedate} = dt_from_string($data->{issuedate}, 'sql'); - $data->{issuedate}->truncate(to => 'minutes'); + $data->{issuedate}->truncate(to => 'minute'); $data->{date_due} = dt_from_string($data->{date_due}, 'sql'); - $data->{date_due}->truncate(to => 'minutes'); - my $dt = DateTime->now( time_zone => C4::Context->tz)->truncate( to => 'minutes'); + $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; } @@ -2129,7 +2182,7 @@ sub GetItemIssues { my ( $itemnumber, $history ) = @_; my $today = DateTime->now( time_zome => C4::Context->tz); # get today date - $today->truncate( to => 'minutes' ); + $today->truncate( to => 'minute' ); my $sql = "SELECT * FROM issues JOIN borrowers USING (borrowernumber) JOIN items USING (itemnumber) @@ -2151,7 +2204,7 @@ sub GetItemIssues { my $results = $sth->fetchall_arrayref({}); foreach (@$results) { my $date_due = dt_from_string($_->{date_due},'sql'); - $date_due->truncate( to => 'minutes' ); + $date_due->truncate( to => 'minute' ); $_->{overdue} = (DateTime->compare($date_due, $today) == -1) ? 1 : 0; } @@ -2744,11 +2797,14 @@ sub SendCirculationAlert { borrowernumber => $borrower->{borrowernumber}, message_name => $message_name{$type}, }); + my $issues_table = ( $type eq 'CHECKOUT' ) ? 'issues' : 'old_issues'; my $letter = C4::Letters::GetPreparedLetter ( module => 'circulation', letter_code => $type, branchcode => $branch, tables => { + $issues_table => $item->{itemnumber}, + 'items' => $item->{itemnumber}, 'biblio' => $item->{biblionumber}, 'biblioitems' => $item->{biblionumber}, 'borrowers' => $borrower, @@ -3082,10 +3138,12 @@ sub ReturnLostItem{ 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 @datearr = localtime(time); my $date = ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3]; my $bor = "$borrower->{'firstname'} $borrower->{'surname'} $borrower->{'cardnumber'}"; - ModItem({ paidfor => "Paid for by $bor $date" }, undef, $itemnum); + ModItem({ paidfor => $old_note."Paid for by $bor $date" }, undef, $itemnum); }