package C4::Circulation::Fines;

# $Id$

# Copyright 2000-2002 Katipo Communications
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA  02111-1307 USA

use strict;
require Exporter;
use DBI;
use C4::Context;
use vars qw($VERSION @ISA @EXPORT);

# set the version for version checking
$VERSION = 0.01;

=head1 NAME

C4::Circulation::Fines - Koha module dealing with fines

=head1 SYNOPSIS

  use C4::Circulation::Fines;

=head1 DESCRIPTION

This module contains several functions for dealing with fines for
overdue items. It is primarily used by the 'misc/fines2.pl' script.

=head1 FUNCTIONS

=over 2

=cut

@ISA    = qw(Exporter);
@EXPORT = qw(&Getoverdues &CalcFine &BorType &UpdateFine &ReplacementCost
  GetFine, ReplacementCost2);

=item Getoverdues

  ($count, $overdues) = &Getoverdues();

Returns the list of all overdue books.

C<$count> is the number of elements in C<@{$overdues}>.

C<$overdues> is a reference-to-array. Each element is a
reference-to-hash whose keys are the fields of the issues table in the
Koha database.

=cut

#'
sub Getoverdues {
    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare(
        "Select * from issues where date_due < now() and returndate is
  NULL order by borrowernumber"
    );
    $sth->execute;

    # FIXME - Use push @results
    my $i = 0;
    my @results;
    while ( my $data = $sth->fetchrow_hashref ) {
        $results[$i] = $data;
        $i++;
    }
    $sth->finish;

    #  print @results;
    # FIXME - Bogus API.
    return ( $i, \@results );
}

=item CalcFine

  ($amount, $chargename, $message) =
	&CalcFine($itemnumber, $borrowercode, $days_overdue);

Calculates the fine for a book.

The issuingrules table in the Koha database is a fine matrix, listing
the penalties for each type of patron for each type of item and each branch (e.g., the
standard fine for books might be $0.50, but $1.50 for DVDs, or staff
members might get a longer grace period between the first and second
reminders that a book is overdue).

The fine is calculated as follows: if it is time for the first
reminder, the fine is the value listed for the given (branch, item type,
borrower code) combination. If it is time for the second reminder, the
fine is doubled. Finally, if it is time to send the account to a
collection agency, the fine is set to 5 local monetary units (a really
good deal for the patron if the library is in Italy). Otherwise, the
fine is 0.

Note that the way this function is currently implemented, it only
returns a nonzero value on the notable days listed above. That is, if
the categoryitems entry says to send a first reminder 7 days after the
book is due, then if you call C<&CalcFine> 7 days after the book is
due, it will give a nonzero fine. If you call C<&CalcFine> the next
day, however, it will say that the fine is 0.

C<$itemnumber> is the book's item number.

C<$borrowercode> is the borrower code of the patron who currently has
the book.

C<$days_overdue> is the number of days elapsed since the book's due
date.

C<&CalcFine> returns a list of three values:

C<$amount> is the fine owed by the patron (see above).

C<$chargename> is the chargename field from the applicable record in
the categoryitem table, whatever that is.

C<$message> is a text message, either "First Notice", "Second Notice",
or "Final Notice".

=cut

#'
sub CalcFine {
    my ( $itemnumber, $bortype, $difference ) = @_;
    my $dbh = C4::Context->dbh;

    # Look up the categoryitem record for this book's item type and the
    # given borrwer type.
    # The reason this query is so messy is that it's a messy question:
    # given the barcode, we can find the book's items record. This gives
    # us the biblioitems record, which gives us a set of categoryitem
    # records. Then we select the one that corresponds to the desired
    # borrower type.

    # FIXME - Is it really necessary to get absolutely everything from
    # all four tables? It looks as if this code only wants
    # firstremind, chargeperiod, accountsent, and chargename from the
    # categoryitem table.

    my $sth = $dbh->prepare(
"SELECT * FROM items,biblioitems,itemtypes,issuingrules
  WHERE items.itemnumber=?
  AND items.biblioitemnumber=biblioitems.biblioitemnumber 
  AND biblioitems.itemtype=itemtypes.itemtype 
  AND issuingrules.itemtype=itemtypes.itemtype 
  AND issuingrules.categorycode=? AND  (items.itemlost <> 1 OR items.itemlost is NULL)"
    );

    #  print $query;
    $sth->execute( $itemnumber, $bortype );
    my $data = $sth->fetchrow_hashref;

    # FIXME - Error-checking: the item might be lost, or there
    # might not be an entry in 'categoryitem' for this item type
    # or borrower type.
    $sth->finish;
    my $amount = 0;
    my $printout;

    # Is it time to send out the first reminder?
    # FIXME - I'm not sure the "=="s are correct here. Let's say that
    # $data->{firstremind} is today, but 'fines2.pl' doesn't run for
    # some reason (the cron daemon died, the server crashed, the
    # sysadmin had the machine down for maintenance, or whatever).
    #
    # Then the next day, the book is $data->{firstremind}+1 days
    # overdue. But this function returns $amount == 0, $printout ==
    # undef, on the assumption that 'fines2.pl' ran the previous day. So
    # the first thing the patron gets is a second notice, but that's a
    # week after the server crash, so people may not connect the two
    # events.
    if ( $difference == $data->{'firstremind'} ) {

        # Yes. Set the fine as listed.
        $amount   = $data->{'fine'};
        $printout = "First Notice";
    }

    # Is it time to send out a second reminder?
    my $second = $data->{'firstremind'} + $data->{'chargeperiod'};
    if ( $difference == $second ) {

        # Yes. The fine is double.
        $amount   = $data->{'fine'} * 2;
        $printout = "Second Notice";
    }

    # Is it time to send the account to a collection agency?
    # FIXME - At least, I *think* that's what this code is doing.
    if ( $difference == $data->{'accountsent'} && $data->{'fine'} > 0 ) {

        # Yes. Set the fine at 5 local monetary units.
        # FIXME - This '5' shouldn't be hard-wired.
        $amount   = 5;
        $printout = "Final Notice";
    }
    return ( $amount, $data->{'chargename'}, $printout );
}

=item UpdateFine

  &UpdateFine($itemnumber, $borrowernumber, $amount, $type, $description);

(Note: the following is mostly conjecture and guesswork.)

Updates the fine owed on an overdue book.

C<$itemnumber> is the book's item number.

C<$borrowernumber> is the borrower number of the patron who currently
has the book on loan.

C<$amount> is the current amount owed by the patron.

C<$type> will be used in the description of the fine.

C<$description> is a string that must be present in the description of
the fine. I think this is expected to be a date in DD/MM/YYYY format.

C<&UpdateFine> looks up the amount currently owed on the given item
and sets it to C<$amount>, creating, if necessary, a new entry in the
accountlines table of the Koha database.

=cut

#'
# FIXME - This API doesn't look right: why should the caller have to
# specify both the item number and the borrower number? A book can't
# be on loan to two different people, so the item number should be
# sufficient.
sub UpdateFine {
    my ( $itemnum, $bornum, $amount, $type, $due ) = @_;
    my $dbh = C4::Context->dbh;

    # FIXME - What exactly is this query supposed to do? It looks up an
    # entry in accountlines that matches the given item and borrower
    # numbers, where the description contains $due, and where the
    # account type has one of several values, but what does this _mean_?
    # Does it look up existing fines for this item?
    # FIXME - What are these various account types? ("FU", "O", "F", "M")
    my $sth = $dbh->prepare(
        "Select * from accountlines where itemnumber=? and
  borrowernumber=? and (accounttype='FU' or accounttype='O' or
  accounttype='F' or accounttype='M') and description like ?"
    );
    $sth->execute( $itemnum, $bornum, "%$due%" );

    if ( my $data = $sth->fetchrow_hashref ) {

        # I think this if-clause deals with the case where we're updating
        # an existing fine.
        #    print "in accounts ...";
        if ( $data->{'amount'} != $amount ) {

            #      print "updating";
            my $diff = $amount - $data->{'amount'};
            my $out  = $data->{'amountoutstanding'} + $diff;
            my $sth2 = $dbh->prepare(
                "update accountlines set date=now(), amount=?,
      amountoutstanding=?,accounttype='FU' where
      borrowernumber=? and itemnumber=?
      and (accounttype='FU' or accounttype='O') and description like ?"
            );
            $sth2->execute( $amount, $out, $data->{'borrowernumber'},
                $data->{'itemnumber'}, "%$due%" );
            $sth2->finish;
        }
        else {

            #      print "no update needed $data->{'amount'}"
        }
    }
    else {

        # I think this else-clause deals with the case where we're adding
        # a new fine.
        my $sth4 = $dbh->prepare(
            "select title from biblio,items where items.itemnumber=?
    and biblio.biblionumber=items.biblionumber"
        );
        $sth4->execute($itemnum);
        my $title = $sth4->fetchrow_hashref;
        $sth4->finish;

        #   print "not in account";
        my $sth3 = $dbh->prepare("Select max(accountno) from accountlines");
        $sth3->execute;

        # FIXME - Make $accountno a scalar.
        my @accountno = $sth3->fetchrow_array;
        $sth3->finish;
        $accountno[0]++;
        my $sth2 = $dbh->prepare(
            "Insert into accountlines
    (borrowernumber,itemnumber,date,amount,
    description,accounttype,amountoutstanding,accountno) values
    (?,?,now(),?,?,'FU',?,?)"
        );
        $sth2->execute( $bornum, $itemnum, $amount,
            "$type $title->{'title'} $due",
            $amount, $accountno[0] );
        $sth2->finish;
    }
    $sth->finish;
}

=item BorType

  $borrower = &BorType($borrowernumber);

Looks up a patron by borrower number.

C<$borrower> is a reference-to-hash whose keys are all of the fields
from the borrowers and categories tables of the Koha database. Thus,
C<$borrower> contains all information about both the borrower and
category he or she belongs to.

=cut

#'
sub BorType {
    my ($borrowernumber) = @_;
    my $dbh              = C4::Context->dbh;
    my $sth              = $dbh->prepare(
        "Select * from borrowers,categories where
  borrowernumber=? and
borrowers.categorycode=categories.categorycode"
    );
    $sth->execute($borrowernumber);
    my $data = $sth->fetchrow_hashref;
    $sth->finish;
    return ($data);
}

=item ReplacementCost

  $cost = &ReplacementCost($itemnumber);

Returns the replacement cost of the item with the given item number.

=cut

#'
sub ReplacementCost {
    my ($itemnum) = @_;
    my $dbh       = C4::Context->dbh;
    my $sth       =
      $dbh->prepare("Select replacementprice from items where itemnumber=?");
    $sth->execute($itemnum);

    # FIXME - Use fetchrow_array or something.
    my $data = $sth->fetchrow_hashref;
    $sth->finish;
    return ( $data->{'replacementprice'} );
}

sub GetFine {
    my ( $itemnum, $bornum ) = @_;
    my $dbh   = C4::Context->dbh();
    my $query = "SELECT sum(amountoutstanding) FROM accountlines 
    where accounttype like 'F%'  
  AND amountoutstanding > 0 AND itemnumber = ? AND borrowernumber=?";
    my $sth = $dbh->prepare($query);
    $sth->execute( $itemnum, $bornum );
    my $data = $sth->fetchrow_hashref();
    $sth->finish();
    $dbh->disconnect();
    return ( $data->{'sum(amountoutstanding)'} );
}

sub ReplacementCost2 {
    my ( $itemnum, $bornum ) = @_;
    my $dbh   = C4::Context->dbh();
    my $query = "SELECT amountoutstanding FROM accountlines
    where accounttype like 'L'  AND amountoutstanding > 0 AND
  itemnumber = ? AND borrowernumber= ?";
    my $sth = $dbh->prepare($query);
    $sth->execute( $itemnum, $bornum );
    my $data = $sth->fetchrow_hashref();
    $sth->finish();
    $dbh->disconnect();
    return ( $data->{'amountoutstanding'} );
}
1;
__END__

=back

=head1 AUTHOR

Koha Developement team <info@koha.org>

=cut
