From 8d0bb312840bc1cdc93586ca0390dc62e7e8ec58 Mon Sep 17 00:00:00 2001
From: Kyle M Hall <kyle@bywatersolutions.com>
Date: Wed, 11 Dec 2013 11:08:16 -0500
Subject: [PATCH]  Bug 6427 [Part 9] - Update existing perl modules to support new accounting system

---
 C4/Circulation.pm    |  311 +++++++++++++++++++++------------------------
 C4/Koha.pm           |    2 +
 C4/Members.pm        |  156 ++++++-----------------
 C4/Overdues.pm       |  340 ++++++++++++++++----------------------------------
 C4/Reserves.pm       |   23 ++--
 C4/SIP/ILS/Patron.pm |    2 +-
 6 files changed, 305 insertions(+), 529 deletions(-)

diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index 0a22b76..7321aad 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -30,7 +30,7 @@ use C4::Items;
 use C4::Members;
 use C4::Dates;
 use C4::Dates qw(format_date);
-use C4::Accounts;
+use Koha::Accounts;
 use C4::ItemCirculationAlertPreference;
 use C4::Message;
 use C4::Debug;
@@ -48,6 +48,7 @@ use Data::Dumper;
 use Koha::DateUtils;
 use Koha::Calendar;
 use Koha::Borrower::Debarments;
+use Koha::Database;
 use Carp;
 use Date::Calc qw(
   Today
@@ -1275,7 +1276,7 @@ sub AddIssue {
         ## 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'} );
+                _FixAccountForLostAndReturned( $item->{'itemnumber'} );
             }
         }
 
@@ -1812,9 +1813,15 @@ sub AddReturn {
                 if ( $amount > 0
                     && C4::Context->preference('finesMode') eq 'production' )
                 {
-                    C4::Overdues::UpdateFine( $issue->{itemnumber},
-                        $issue->{borrowernumber},
-                        $amount, $type, output_pref($datedue) );
+                    C4::Overdues::UpdateFine(
+                        {
+                            itemnumber     => $issue->{itemnumber},
+                            borrowernumber => $issue->{borrowernumber},
+                            amount         => $amount,
+                            due            => output_pref($datedue),
+                            issue_id       => $issue->{issue_id}
+                        }
+                    );
                 }
             }
 
@@ -1864,18 +1871,23 @@ sub AddReturn {
         $messages->{'WasLost'} = 1;
 
         if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) {
-            _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode);    # can tolerate undef $borrowernumber
+            _FixAccountForLostAndReturned( $item->{'itemnumber'} );
             $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
+        _FixOverduesOnReturn(
+            {
+                exempt_fine => $exemptfine,
+                dropbox     => $dropbox,
+                issue       => $issue,
+            }
+        );
         
         if ( $issue->{overdue} && $issue->{date_due} ) {
-# fix fine days
+            # fix fine days
             my $debardate =
               _debar_user_on_return( $borrower, $item, $issue->{date_due}, $today );
             $messages->{Debarred} = $debardate if ($debardate);
@@ -2093,139 +2105,107 @@ Internal function, called only by AddReturn
 =cut
 
 sub _FixOverduesOnReturn {
-    my ($borrowernumber, $item);
-    unless ($borrowernumber = shift) {
-        warn "_FixOverduesOnReturn() not supplied valid borrowernumber";
-        return;
-    }
-    unless ($item = shift) {
-        warn "_FixOverduesOnReturn() not supplied valid itemnumber";
-        return;
-    }
-    my ($exemptfine, $dropbox) = @_;
+    my ( $params ) = @_;
+
+    my $exemptfine = $params->{exempt_fine};
+    my $dropbox    = $params->{dropbox};
+    my $issue      = $params->{issue};
+
     my $dbh = C4::Context->dbh;
 
-    # check for overdue fine
-    my $sth = $dbh->prepare(
-"SELECT * FROM accountlines WHERE (borrowernumber = ?) AND (itemnumber = ?) AND (accounttype='FU' OR accounttype='O')"
-    );
-    $sth->execute( $borrowernumber, $item );
+    my $schema = Koha::Database->new()->schema;
+    my $fine =
+      $schema->resultset('AccountDebit')
+      ->single( { issue_id => $issue->issue_id(), type => Koha::Accounts::DebitTypes::Fine() } );
 
-    # alter fine to show that the book has been returned
-    my $data = $sth->fetchrow_hashref;
-    return 0 unless $data;    # no warning, there's just nothing to fix
+    return unless ( $fine );
+
+    $fine->accruing(0);
 
-    my $uquery;
-    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} ;
+        AddCredit(
+            {
+                borrower => $fine->borrowernumber(),
+                amount   => $fine->amount_original(),
+                debit_id => $fine->debit_id(),
+                type     => Koha::Accounts::CreditTypes::Forgiven(),
+            }
+        );
         if (C4::Context->preference("FinesLog")) {
-            &logaction("FINES", 'MODIFY',$borrowernumber,"Dropbox adjustment $amt, item $item");
+            &logaction(
+                "FINES", 'MODIFY',
+                $issue->borrowernumber(),
+                "Overdue forgiven: item " . $issue->itemnumber()
+            );
         }
-         $uquery = "update accountlines set accounttype='F' ";
-         if($outstanding  >= 0 && $amt >=0) {
-            $uquery .= ", amount = ? , amountoutstanding=? ";
-            unshift @bind, ($amt, $outstanding) ;
+    } elsif ($dropbox && $fine->amount_last_increment() != $fine->amount_original() ) {
+        if ( C4::Context->preference("FinesLog") ) {
+            &logaction( "FINES", 'MODIFY', $issue->borrowernumber(),
+                    "Dropbox adjustment "
+                  . $fine->amount_last_increment()
+                  . ", item " . $issue->itemnumber() );
         }
-    } else {
-        $uquery = "update accountlines set accounttype='F' ";
+        $fine->amount_original(
+            $fine->amount_original() - $fine->amount_last_increment() );
+        $fine->amount_outstanding(
+            $fine->amount_outstanding - $fine->amount_last_increment() );
+        $schema->resultset('AccountOffset')->create(
+            {
+                debit_id => $fine->debit_id(),
+                type     => Koha::Accounts::OffsetTypes::Dropbox(),
+                amount   => $fine->amount_last_increment() * -1,
+            }
+        );
     }
-    $uquery .= " where (accountlines_id = ?)";
-    my $usth = $dbh->prepare($uquery);
-    return $usth->execute(@bind);
+
+    return $fine->update();
 }
 
 =head2 _FixAccountForLostAndReturned
 
-  &_FixAccountForLostAndReturned($itemnumber, [$borrowernumber, $barcode]);
-
-Calculates the charge for a book lost and returned.
+  &_FixAccountForLostAndReturned($itemnumber);
 
-Internal function, not exported, called only by AddReturn.
-
-FIXME: This function reflects how inscrutable fines logic is.  Fix both.
-FIXME: Give a positive return value on success.  It might be the $borrowernumber who received credit, or the amount forgiven.
+  Refunds a lost item fee in necessary
 
 =cut
 
 sub _FixAccountForLostAndReturned {
-    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 $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");
-    $sth->execute($itemnumber);
-    my $data = $sth->fetchrow_hashref;
-    $data or return;    # bail if there is nothing to do
-    $data->{accounttype} eq 'W' and return;    # Written off
-
-    # writeoff this amount
-    my $offset;
-    my $amount = $data->{'amount'};
-    my $acctno = $data->{'accountno'};
-    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'});
-        # offset transactions
-        my $newamtos;
-        my $accdata;
-        while (($accdata=$msth->fetchrow_hashref) and ($amountleft>0)){
-            if ($accdata->{'amountoutstanding'} < $amountleft) {
-                $newamtos = 0;
-                $amountleft -= $accdata->{'amountoutstanding'};
-            }  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
-                (borrowernumber, accountno, offsetaccount,  offsetamount)
-                VALUES
-                (?,?,?,?)");
-            $usth->execute($data->{'borrowernumber'},$accdata->{'accountno'},$nextaccntno,$newamtos);
+    my ( $itemnumber ) = @_;
+
+    my $schema = Koha::Database->new()->schema;
+
+    # Find the last issue for this item
+    my $issue =
+      $schema->resultset('Issue')->single( { itemnumber => $itemnumber } );
+    $issue ||=
+      $schema->resultset('OldIssue')->single( { itemnumber => $itemnumber } );
+
+    return unless $issue;
+
+    # Find a lost fee for this issue
+    my $debit = $schema->resultset('AccountDebit')->single(
+        {
+            issue_id => $issue->issue_id(),
+            type     => Koha::Accounts::DebitTypes::Lost()
         }
-    }
-    $amountleft *= -1 if ($amountleft > 0);
-    my $desc = "Item Returned " . $item_id;
-    $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);
-    if ($borrowernumber) {
-        # FIXME: same as query above.  use 1 sth for both
-        $usth = $dbh->prepare("INSERT INTO accountoffsets
-            (borrowernumber, accountno, offsetaccount,  offsetamount)
-            VALUES (?,?,?,?)");
-        $usth->execute($borrowernumber, $data->{'accountno'}, $nextaccntno, $offset);
-    }
+    );
+
+    return unless $debit;
+
+    # Check for an existing found credit for this debit, if there is one, the fee has already been refunded and we do nothing
+    my @credits = $debit->account_offsets->search_related('credit', { 'credit.type' => Koha::Accounts::CreditTypes::Found() });
+
+    return if @credits;
+
+    # Ok, so we know we have an unrefunded lost item fee, let's refund it
+    CreditLostItem(
+        {
+            borrower => $issue->borrower(),
+            debit    => $debit
+        }
+    );
+
     ModItem({ paidfor => '' }, undef, $itemnumber);
-    return;
 }
 
 =head2 _GetCircControlBranch
@@ -2584,19 +2564,22 @@ sub AddRenewal {
     # 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 $manager_id = 0;
-        $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; 
-        $sth = $dbh->prepare(
-                "INSERT INTO accountlines
-                    (date, borrowernumber, accountno, amount, manager_id,
-                    description,accounttype, amountoutstanding, itemnumber)
-                    VALUES (now(),?,?,?,?,?,?,?,?)"
+
+        my $borrower =
+          Koha::Database->new()->schema->resultset('Borrower')
+          ->find($borrowernumber);
+
+        AddDebit(
+            {
+                borrower   => $borrower,
+                itemnumber => $itemnumber,
+                amount     => $charge,
+                type       => Koha::Accounts::DebitTypes::Rental(),
+                description =>
+                  "Renewal of Rental Item $item->{'title'} $item->{'barcode'}"
+            }
         );
-        $sth->execute( $borrowernumber, $accountno, $charge, $manager_id,
-            "Renewal of Rental Item $item->{'title'} $item->{'barcode'}",
-            'Rent', $charge, $itemnumber );
     }
 
     # Send a renewal slip according to checkout alert preferencei
@@ -2767,25 +2750,21 @@ sub _get_discount_from_rule {
 
 =head2 AddIssuingCharge
 
-  &AddIssuingCharge( $itemno, $borrowernumber, $charge )
+  &AddIssuingCharge( $itemnumber, $borrowernumber, $amount )
 
 =cut
 
 sub AddIssuingCharge {
-    my ( $itemnumber, $borrowernumber, $charge ) = @_;
-    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 ="
-        INSERT INTO accountlines
-            (borrowernumber, itemnumber, accountno,
-            date, amount, description, accounttype,
-            amountoutstanding, manager_id)
-        VALUES (?, ?, ?,now(), ?, 'Rental', 'Rent',?,?)
-    ";
-    my $sth = $dbh->prepare($query);
-    $sth->execute( $borrowernumber, $itemnumber, $nextaccntno, $charge, $charge, $manager_id );
+    my ( $itemnumber, $borrowernumber, $amount ) = @_;
+
+    return AddDebit(
+        {
+            borrower       => Koha::Database->new()->schema->resultset('Borrower')->find($borrowernumber),
+            itemnumber     => $itemnumber,
+            amount         => $amount,
+            type           => Koha::Accounts::DebitTypes::Rental(),
+        }
+    );
 }
 
 =head2 GetTransfers
@@ -3304,30 +3283,30 @@ sub ReturnLostItem{
 sub LostItem{
     my ($itemnumber, $mark_returned) = @_;
 
-    my $dbh = C4::Context->dbh();
-    my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title 
-                           FROM issues 
-                           JOIN items USING (itemnumber) 
-                           JOIN biblio USING (biblionumber)
-                           WHERE issues.itemnumber=?");
-    $sth->execute($itemnumber);
-    my $issues=$sth->fetchrow_hashref();
+    my $schema = Koha::Database->new()->schema;
 
-    # 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 );
+    my $issue =
+      $schema->resultset('Issue')->single( { itemnumber => $itemnumber } );
 
+    my $borrower = $issue->borrower();
+    my $item     = $issue->item();
+
+    # If a borrower lost the item, add a replacement cost to the their record
+    if ( $borrower ){
         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
+            _FixOverduesOnReturn(
+                {
+                    exempt_fine => 1,
+                    dropbox     => 0,
+                    issue       => $issue,
+                }
+            );
         }
-        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 ";
+        if ( C4::Context->preference('WhenLostChargeReplacementFee') ) {
+            DebitLostItem( { borrower => $borrower, issue => $issue } );
         }
 
-        MarkIssueReturned($borrowernumber,$itemnumber,undef,undef,$borrower->{'privacy'}) if $mark_returned;
+        MarkIssueReturned( $borrower->borrowernumber(), $item->itemnumber(), undef, undef, $borrower->privacy() ) if $mark_returned;
     }
 }
 
diff --git a/C4/Koha.pm b/C4/Koha.pm
index 937ac5f..4b9c4c5 100644
--- a/C4/Koha.pm
+++ b/C4/Koha.pm
@@ -1029,6 +1029,7 @@ C<$opac> If set to a true value, displays OPAC descriptions rather than normal o
 
 sub GetAuthorisedValues {
     my ( $category, $selected, $opac ) = @_;
+    warn "GetAuthorisedValues( $category, $selected, $opac )";
     my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
     my @results;
     my $dbh      = C4::Context->dbh;
@@ -1075,6 +1076,7 @@ sub GetAuthorisedValues {
         push @results, $data;
     }
     $sth->finish;
+    warn "RET: " . Data::Dumper::Dumper( \@results );
     return \@results;
 }
 
diff --git a/C4/Members.pm b/C4/Members.pm
index b04cc64..b45147d 100644
--- a/C4/Members.pm
+++ b/C4/Members.pm
@@ -29,7 +29,6 @@ use Date::Calc qw/Today Add_Delta_YM check_date Date_to_Days/;
 use C4::Log; # logaction
 use C4::Overdues;
 use C4::Reserves;
-use C4::Accounts;
 use C4::Biblio;
 use C4::Letters;
 use C4::SQLHelper qw(InsertInTable UpdateInTable SearchInTable);
@@ -41,6 +40,7 @@ use Koha::DateUtils;
 use Koha::Borrower::Debarments qw(IsDebarred);
 use Text::Unaccent qw( unac_string );
 use Koha::AuthUtils qw(hash_password);
+use Koha::Accounts::DebitTypes;
 
 our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
 
@@ -83,8 +83,6 @@ BEGIN {
         &GetHideLostItemsPreference
 
         &IsMemberBlocked
-        &GetMemberAccountRecords
-        &GetBorNotifyAcctRecord
 
         &GetborCatFromCatType
         &GetBorrowercategory
@@ -338,9 +336,6 @@ sub GetMemberDetails {
         return;
     }
     my $borrower = $sth->fetchrow_hashref;
-    my ($amount) = GetMemberAccountRecords( $borrowernumber);
-    $borrower->{'amountoutstanding'} = $amount;
-    # FIXME - patronflags calls GetMemberAccountRecords... just have patronflags return $amount
     my $flags = patronflags( $borrower);
     my $accessflagshash;
 
@@ -432,23 +427,20 @@ The "message" field that comes from the DB is OK.
 # FIXME rename this function.
 sub patronflags {
     my %flags;
-    my ( $patroninformation) = @_;
-    my $dbh=C4::Context->dbh;
-    my ($balance, $owing) = GetMemberAccountBalance( $patroninformation->{'borrowernumber'});
-    if ( $owing > 0 ) {
+    my ($patroninformation) = @_;
+    my $dbh = C4::Context->dbh;
+    if ( $patroninformation->{account_balance} > 0 ) {
         my %flaginfo;
         my $noissuescharge = C4::Context->preference("noissuescharge") || 5;
-        $flaginfo{'message'} = sprintf 'Patron owes %.02f', $owing;
-        $flaginfo{'amount'}  = sprintf "%.02f", $owing;
-        if ( $owing > $noissuescharge && !C4::Context->preference("AllowFineOverride") ) {
+        $flaginfo{'amount'}  = $patroninformation->{account_balance};
+        if (  $patroninformation->{account_balance} > $noissuescharge && !C4::Context->preference("AllowFineOverride") ) {
             $flaginfo{'noissues'} = 1;
         }
         $flags{'CHARGES'} = \%flaginfo;
     }
-    elsif ( $balance < 0 ) {
+    elsif ( $patroninformation->{account_balance} < 0 ) {
         my %flaginfo;
-        $flaginfo{'message'} = sprintf 'Patron has credit of %.02f', -$balance;
-        $flaginfo{'amount'}  = sprintf "%.02f", $balance;
+        $flaginfo{'amount'}  = $patroninformation->{account_balance};
         $flags{'CREDITS'} = \%flaginfo;
     }
     if (   $patroninformation->{'gonenoaddress'}
@@ -691,7 +683,7 @@ sub GetMemberIssuesAndFines {
     $sth->execute($borrowernumber);
     my $overdue_count = $sth->fetchrow_arrayref->[0];
 
-    $sth = $dbh->prepare("SELECT SUM(amountoutstanding) FROM accountlines WHERE borrowernumber = ?");
+    $sth = $dbh->prepare("SELECT account_balance FROM borrowers WHERE borrowernumber = ?");
     $sth->execute($borrowernumber);
     my $total_fines = $sth->fetchrow_arrayref->[0];
 
@@ -1167,57 +1159,14 @@ sub GetAllIssues {
 }
 
 
-=head2 GetMemberAccountRecords
-
-  ($total, $acctlines, $count) = &GetMemberAccountRecords($borrowernumber);
-
-Looks up accounting data for the patron with the given borrowernumber.
-
-C<&GetMemberAccountRecords> returns a three-element array. C<$acctlines> is a
-reference-to-array, where each element is a reference-to-hash; the
-keys are the fields of the C<accountlines> table in the Koha database.
-C<$count> is the number of elements in C<$acctlines>. C<$total> is the
-total amount outstanding for all of the account lines.
-
-=cut
-
-sub GetMemberAccountRecords {
-    my ($borrowernumber) = @_;
-    my $dbh = C4::Context->dbh;
-    my @acctlines;
-    my $numlines = 0;
-    my $strsth      = qq(
-                        SELECT * 
-                        FROM accountlines 
-                        WHERE borrowernumber=?);
-    $strsth.=" ORDER BY date desc,timestamp DESC";
-    my $sth= $dbh->prepare( $strsth );
-    $sth->execute( $borrowernumber );
-
-    my $total = 0;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        if ( $data->{itemnumber} ) {
-            my $biblio = GetBiblioFromItemNumber( $data->{itemnumber} );
-            $data->{biblionumber} = $biblio->{biblionumber};
-            $data->{title}        = $biblio->{title};
-        }
-        $acctlines[$numlines] = $data;
-        $numlines++;
-        $total += int(1000 * $data->{'amountoutstanding'}); # convert float to integer to avoid round-off errors
-    }
-    $total /= 1000;
-    return ( $total, \@acctlines,$numlines);
-}
-
 =head2 GetMemberAccountBalance
 
   ($total_balance, $non_issue_balance, $other_charges) = &GetMemberAccountBalance($borrowernumber);
 
 Calculates amount immediately owing by the patron - non-issue charges.
-Based on GetMemberAccountRecords.
 Charges exempt from non-issue are:
-* Res (reserves)
-* Rent (rental) if RentalsInNoissuesCharge syspref is set to false
+* HOLD fees (reserves)
+* RENTAL if RentalsInNoissuesCharge syspref is set to false
 * Manual invoices if ManInvInNoissuesCharge syspref is set to false
 
 =cut
@@ -1225,70 +1174,41 @@ Charges exempt from non-issue are:
 sub GetMemberAccountBalance {
     my ($borrowernumber) = @_;
 
-    my $ACCOUNT_TYPE_LENGTH = 5; # this is plain ridiculous...
+    my $borrower =
+      Koha::Database->new()->schema->resultset('Borrower')
+      ->find($borrowernumber);
 
-    my @not_fines = ('Res');
-    push @not_fines, 'Rent' unless C4::Context->preference('RentalsInNoissuesCharge');
-    unless ( C4::Context->preference('ManInvInNoissuesCharge') ) {
-        my $dbh = C4::Context->dbh;
-        my $man_inv_types = $dbh->selectcol_arrayref(qq{SELECT authorised_value FROM authorised_values WHERE category = 'MANUAL_INV'});
-        push @not_fines, map substr($_, 0, $ACCOUNT_TYPE_LENGTH), @$man_inv_types;
-    }
-    my %not_fine = map {$_ => 1} @not_fines;
+    my @not_fines;
 
-    my ($total, $acctlines) = GetMemberAccountRecords($borrowernumber);
-    my $other_charges = 0;
-    foreach (@$acctlines) {
-        $other_charges += $_->{amountoutstanding} if $not_fine{ substr($_->{accounttype}, 0, $ACCOUNT_TYPE_LENGTH) };
-    }
-
-    return ( $total, $total - $other_charges, $other_charges);
-}
-
-=head2 GetBorNotifyAcctRecord
-
-  ($total, $acctlines, $count) = &GetBorNotifyAcctRecord($params,$notifyid);
+    push( @not_fines, Koha::Accounts::DebitTypes::Hold() );
 
-Looks up accounting data for the patron with the given borrowernumber per file number.
+    push( @not_fines, Koha::Accounts::DebitTypes::Rental() )
+      unless C4::Context->preference('RentalsInNoissuesCharge');
 
-C<&GetBorNotifyAcctRecord> returns a three-element array. C<$acctlines> is a
-reference-to-array, where each element is a reference-to-hash; the
-keys are the fields of the C<accountlines> table in the Koha database.
-C<$count> is the number of elements in C<$acctlines>. C<$total> is the
-total amount outstanding for all of the account lines.
-
-=cut
+    unless ( C4::Context->preference('ManInvInNoissuesCharge') ) {
+        my $dbh           = C4::Context->dbh;
+        my $man_inv_types = $dbh->selectcol_arrayref(
+            qq{SELECT authorised_value FROM authorised_values WHERE category = 'MANUAL_INV'}
+        );
+        push( @not_fines, @$man_inv_types );
+    }
 
-sub GetBorNotifyAcctRecord {
-    my ( $borrowernumber, $notifyid ) = @_;
-    my $dbh = C4::Context->dbh;
-    my @acctlines;
-    my $numlines = 0;
-    my $sth = $dbh->prepare(
-            "SELECT * 
-                FROM accountlines 
-                WHERE borrowernumber=? 
-                    AND notify_id=? 
-                    AND amountoutstanding != '0' 
-                ORDER BY notify_id,accounttype
-                ");
-
-    $sth->execute( $borrowernumber, $notifyid );
-    my $total = 0;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        if ( $data->{itemnumber} ) {
-            my $biblio = GetBiblioFromItemNumber( $data->{itemnumber} );
-            $data->{biblionumber} = $biblio->{biblionumber};
-            $data->{title}        = $biblio->{title};
+    my $other_charges =
+      Koha::Database->new()->schema->resultset('AccountDebit')->search(
+        {
+            borrowernumber => $borrowernumber,
+            type           => { -not_in => \@not_fines }
         }
-        $acctlines[$numlines] = $data;
-        $numlines++;
-        $total += int(100 * $data->{'amountoutstanding'});
-    }
-    $total /= 100;
-    return ( $total, \@acctlines, $numlines );
+      )->get_column('amount_outstanding')->sum();
+
+    return (
+        $borrower->account_balance(),
+        $borrower->account_balance() - $other_charges,
+        $other_charges
+    );
 }
 
+
 =head2 checkuniquemember (OUEST-PROVENCE)
 
   ($result,$categorycode)  = &checkuniquemember($collectivity,$surname,$firstname,$dateofbirth);
diff --git a/C4/Overdues.pm b/C4/Overdues.pm
index 33dbd98..0764dd4 100644
--- a/C4/Overdues.pm
+++ b/C4/Overdues.pm
@@ -25,9 +25,10 @@ use Date::Calc qw/Today Date_to_Days/;
 use Date::Manip qw/UnixDate/;
 use C4::Circulation;
 use C4::Context;
-use C4::Accounts;
 use C4::Log; # logaction
 use C4::Debug;
+use Koha::Database;
+use Koha::DateUtils;
 
 use vars qw($VERSION @ISA @EXPORT);
 
@@ -41,12 +42,9 @@ BEGIN {
         &CalcFine
         &Getoverdues
         &checkoverdues
-        &NumberNotifyId
-        &AmountNotify
         &UpdateFine
         &GetFine
         
-        &CheckItemNotify
         &GetOverduesForBranch
         &RemoveNotifyLine
         &AddNotifyLine
@@ -456,154 +454,112 @@ sub GetIssuesIteminfo {
 
 =head2 UpdateFine
 
-    &UpdateFine($itemnumber, $borrowernumber, $amount, $type, $description);
+    UpdateFine(
+        {
+            itemnumber     => $itemnumber,
+            borrowernumber => $borrowernumber,
+            amount         => $amount,
+            due            => $due,
+            issue_id       => $issue_id
+        }
+    );
 
-(Note: the following is mostly conjecture and guesswork.)
+Updates the fine owed on an overdue item.
 
-Updates the fine owed on an overdue book.
+C<$itemnumber> is the items's id.
 
-C<$itemnumber> is the book's item number.
+C<$borrowernumber> is the id of the patron who currently
+has the item on loan.
 
-C<$borrowernumber> is the borrower number of the patron who currently
-has the book on loan.
+C<$amount> is the total amount of the fine owed by the patron.
 
-C<$amount> is the current amount owed by the patron.
+C<&UpdateFine> updates the amount owed for a given fine if an issue_id
+is passed to it. Otherwise, a new fine will be created.
 
-C<$type> will be used in the description of the fine.
+=cut
 
-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.
+sub UpdateFine {
+    my ($params) = @_;
 
-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.
+    my $itemnumber     = $params->{itemnumber};
+    my $borrowernumber = $params->{borrowernumber};
+    my $amount         = $params->{amount};
+    my $due            = $params->{due};
+    my $issue_id       = $params->{issue_id};
 
-=cut
+    my $schema = Koha::Database->new()->schema;
 
-#
-# Question: 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.
-#
-# Possible Answer: You might update a fine for a damaged item, *after* it is returned.
-#
-sub UpdateFine {
-    my ( $itemnum, $borrowernumber, $amount, $type, $due ) = @_;
-	$debug and warn "UpdateFine($itemnum, $borrowernumber, $amount, " . ($type||'""') . ", $due) called";
-    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")
-	#	"L"   is LOST item
-	#   "A"   is Account Management Fee
-	#   "N"   is New Card
-	#   "M"   is Sundry
-	#   "O"   is Overdue ??
-	#   "F"   is Fine ??
-	#   "FU"  is Fine UPDATE??
-	#	"Pay" is Payment
-	#   "REF" is Cash Refund
-    my $sth = $dbh->prepare(
-        "SELECT * FROM accountlines
-        WHERE borrowernumber=?
-        AND   accounttype IN ('FU','O','F','M')"
-    );
-    $sth->execute( $borrowernumber );
-    my $data;
-    my $total_amount_other = 0.00;
-    my $due_qr = qr/$due/;
-    # Cycle through the fines and
-    # - find line that relates to the requested $itemnum
-    # - accumulate fines for other items
-    # so we can update $itemnum fine taking in account fine caps
-    while (my $rec = $sth->fetchrow_hashref) {
-        if ($rec->{itemnumber} == $itemnum && $rec->{description} =~ /$due_qr/) {
-            if ($data) {
-                warn "Not a unique accountlines record for item $itemnum borrower $borrowernumber";
-            } else {
-                $data = $rec;
-                next;
-            }
-        }
-        $total_amount_other += $rec->{'amountoutstanding'};
-    }
+    my $borrower = $schema->resultset('Borrower')->find($borrowernumber);
 
-    if (my $maxfine = C4::Context->preference('MaxFine')) {
-        if ($total_amount_other + $amount > $maxfine) {
-            my $new_amount = $maxfine - $total_amount_other;
-            return if $new_amount <= 0.00;
-            warn "Reducing fine for item $itemnum borrower $borrowernumber from $amount to $new_amount - MaxFine reached";
+    if ( my $maxfine = C4::Context->preference('MaxFine') ) {
+        if ( $borrower->account_balance() + $amount > $maxfine ) {
+            my $new_amount = $maxfine - $borrower->account_balance();
+            warn "Reducing fine for item $itemnumber borrower $borrowernumber from $amount to $new_amount - MaxFine reached";
+            if ( $new_amount <= 0 ) {
+                warn "Fine reduced to a non-positive ammount. Fine not created.";
+                return;
+            }
             $amount = $new_amount;
         }
     }
 
-    if ( $data ) {
-
-		# we're updating an existing fine.  Only modify if amount changed
-        # Note that in the current implementation, you cannot pay against an accruing fine
-        # (i.e. , of accounttype 'FU').  Doing so will break accrual.
-    	if ( $data->{'amount'} != $amount ) {
-            my $diff = $amount - $data->{'amount'};
-	    #3341: diff could be positive or negative!
-            my $out  = $data->{'amountoutstanding'} + $diff;
-            my $query = "
-                UPDATE accountlines
-				SET date=now(), amount=?, amountoutstanding=?,
-					lastincrement=?, accounttype='FU'
-	  			WHERE borrowernumber=?
-				AND   itemnumber=?
-				AND   accounttype IN ('FU','O')
-				AND   description LIKE ?
-				LIMIT 1 ";
-            my $sth2 = $dbh->prepare($query);
-			# FIXME: BOGUS query cannot ensure uniqueness w/ LIKE %x% !!!
-			# 		LIMIT 1 added to prevent multiple affected lines
-			# FIXME: accountlines table needs unique key!! Possibly a combo of borrowernumber and accountline.  
-			# 		But actually, we should just have a regular autoincrementing PK and forget accountline,
-			# 		including the bogus getnextaccountno function (doesn't prevent conflict on simultaneous ops).
-			# FIXME: Why only 2 account types here?
-			$debug and print STDERR "UpdateFine query: $query\n" .
-				"w/ args: $amount, $out, $diff, $data->{'borrowernumber'}, $data->{'itemnumber'}, \"\%$due\%\"\n";
-            $sth2->execute($amount, $out, $diff, $data->{'borrowernumber'}, $data->{'itemnumber'}, "%$due%");
-        } else {
-            #      print "no update needed $data->{'amount'}"
+    my $timestamp = get_timestamp();
+
+    my $fine =
+      $schema->resultset('AccountDebit')->single( { issue_id => $issue_id } );
+
+    my $offset = 0;
+    if ($fine) {
+        if (
+            sprintf( "%.6f", $fine->amount_original() )
+            ne
+            sprintf( "%.6f", $amount ) )
+        {
+            my $difference = $amount - $fine->amount_original();
+
+            $fine->amount_original( $fine->amount_original() + $difference );
+            $fine->amount_outstanding( $fine->amount_outstanding() + $difference );
+            $fine->amount_last_increment($difference);
+            $fine->updated_on($timestamp);
+            $fine->update();
+
+            $offset = 1;
         }
-    } else {
-        my $sth4 = $dbh->prepare(
-            "SELECT title FROM biblio LEFT JOIN items ON biblio.biblionumber=items.biblionumber WHERE items.itemnumber=?"
+    }
+    else {
+        my $item = $schema->resultset('Item')->find($itemnumber);
+
+        $fine = $schema->resultset('AccountDebit')->create(
+            {
+                borrowernumber        => $borrowernumber,
+                itemnumber            => $itemnumber,
+                issue_id              => $issue_id,
+                type                  => Koha::Accounts::DebitTypes::Fine(),
+                accruing              => 1,
+                amount_original       => $amount,
+                amount_outstanding    => $amount,
+                amount_last_increment => $amount,
+                description           => $item->biblio()->title() . " / Due:$due",
+                created_on            => $timestamp,
+            }
         );
-        $sth4->execute($itemnum);
-        my $title = $sth4->fetchrow;
-
-#         #   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]++;
-# begin transaction
-		my $nextaccntno = C4::Accounts::getnextacctno($borrowernumber);
-		my $desc = ($type ? "$type " : '') . "$title $due";	# FIXEDME, avoid whitespace prefix on empty $type
-		my $query = "INSERT INTO accountlines
-		    (borrowernumber,itemnumber,date,amount,description,accounttype,amountoutstanding,lastincrement,accountno)
-			    VALUES (?,?,now(),?,?,'FU',?,?,?)";
-		my $sth2 = $dbh->prepare($query);
-		$debug and print STDERR "UpdateFine query: $query\nw/ args: $borrowernumber, $itemnum, $amount, $desc, $amount, $amount, $nextaccntno\n";
-        $sth2->execute($borrowernumber, $itemnum, $amount, $desc, $amount, $amount, $nextaccntno);
+
+        $offset = 1;
     }
-    # logging action
-    &logaction(
-        "FINES",
-        $type,
+
+    $schema->resultset('AccountOffset')->create(
+        {
+            debit_id   => $fine->debit_id(),
+            amount     => $fine->amount_last_increment(),
+            created_on => $timestamp,
+            type       => Koha::Accounts::OffsetTypes::Fine(),
+        }
+    ) if $offset;
+
+    logaction( "FINES", Koha::Accounts::DebitTypes::Fine(),
         $borrowernumber,
-        "due=".$due."  amount=".$amount." itemnumber=".$itemnum
-        ) if C4::Context->preference("FinesLog");
+        "due=" . $due . "  amount=" . $amount . " itemnumber=" . $itemnumber )
+      if C4::Context->preference("FinesLog");
 }
 
 =head2 BorType
@@ -644,70 +600,19 @@ C<$borrowernumber> is the borrowernumber
 =cut 
 
 sub GetFine {
-    my ( $itemnum, $borrowernumber ) = @_;
-    my $dbh   = C4::Context->dbh();
-    my $query = q|SELECT sum(amountoutstanding) as fineamount FROM accountlines
-    where accounttype like 'F%'
-  AND amountoutstanding > 0 AND itemnumber = ? AND borrowernumber=?|;
-    my $sth = $dbh->prepare($query);
-    $sth->execute( $itemnum, $borrowernumber );
-    my $fine = $sth->fetchrow_hashref();
-    if ($fine->{fineamount}) {
-        return $fine->{fineamount};
-    }
-    return 0;
-}
-
-=head2 NumberNotifyId
+    my ( $itemnumber, $borrowernumber ) = @_;
 
-    (@notify) = &NumberNotifyId($borrowernumber);
+    my $schema = Koha::Database->new()->schema;
 
-Returns amount for all file per borrowers
-C<@notify> array contains all file per borrowers
+    my $amount_outstanding = $schema->resultset('AccountDebit')->search(
+        {
+            itemnumber     => $itemnumber,
+            borrowernumber => $borrowernumber,
+            type           => Koha::Accounts::DebitTypes::Fine(),
+        },
+    )->get_column('amount_outstanding')->sum();
 
-C<$notify_id> contains the file number for the borrower number nad item number
-
-=cut
-
-sub NumberNotifyId{
-    my ($borrowernumber)=@_;
-    my $dbh = C4::Context->dbh;
-    my $query=qq|    SELECT distinct(notify_id)
-            FROM accountlines
-            WHERE borrowernumber=?|;
-    my @notify;
-    my $sth = $dbh->prepare($query);
-    $sth->execute($borrowernumber);
-    while ( my ($numberofnotify) = $sth->fetchrow ) {
-        push( @notify, $numberofnotify );
-    }
-    return (@notify);
-}
-
-=head2 AmountNotify
-
-    ($totalnotify) = &AmountNotify($notifyid);
-
-Returns amount for all file per borrowers
-C<$notifyid> is the file number
-
-C<$totalnotify> contains amount of a file
-
-C<$notify_id> contains the file number for the borrower number and item number
-
-=cut
-
-sub AmountNotify{
-    my ($notifyid,$borrowernumber)=@_;
-    my $dbh = C4::Context->dbh;
-    my $query=qq|    SELECT sum(amountoutstanding)
-            FROM accountlines
-            WHERE notify_id=? AND borrowernumber = ?|;
-    my $sth=$dbh->prepare($query);
-	$sth->execute($notifyid,$borrowernumber);
-	my $totalnotify=$sth->fetchrow;
-    $sth->finish;
-    return ($totalnotify);
+    return $amount_outstanding;
 }
 
 =head2 GetItems
@@ -759,27 +664,6 @@ sub GetBranchcodesWithOverdueRules {
     return @branches;
 }
 
-=head2 CheckItemNotify
-
-Sql request to check if the document has alreday been notified
-this function is not exported, only used with GetOverduesForBranch
-
-=cut
-
-sub CheckItemNotify {
-    my ($notify_id,$notify_level,$itemnumber) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("
-    SELECT COUNT(*)
-     FROM notifys
-    WHERE notify_id    = ?
-     AND  notify_level = ? 
-     AND  itemnumber   = ? ");
-    $sth->execute($notify_id,$notify_level,$itemnumber);
-    my $notified = $sth->fetchrow;
-    return ($notified);
-}
-
 =head2 GetOverduesForBranch
 
 Sql request for display all information for branchoverdues.pl
@@ -804,6 +688,7 @@ sub GetOverduesForBranch {
                biblio.title,
                biblio.author,
                biblio.biblionumber,
+               issues.issue_id,
                issues.date_due,
                issues.returndate,
                issues.branchcode,
@@ -814,25 +699,23 @@ sub GetOverduesForBranch {
                 items.location,
                 items.itemnumber,
             itemtypes.description,
-         accountlines.notify_id,
-         accountlines.notify_level,
-         accountlines.amountoutstanding
-    FROM  accountlines
-    LEFT JOIN issues      ON    issues.itemnumber     = accountlines.itemnumber
-                          AND   issues.borrowernumber = accountlines.borrowernumber
-    LEFT JOIN borrowers   ON borrowers.borrowernumber = accountlines.borrowernumber
+            account_debits.amount_outstanding
+    FROM  account_debits
+    LEFT JOIN issues      ON    issues.itemnumber     = account_debits.itemnumber
+                          AND   issues.borrowernumber = account_debits.borrowernumber
+    LEFT JOIN borrowers   ON borrowers.borrowernumber = account_debits.borrowernumber
     LEFT JOIN items       ON     items.itemnumber     = issues.itemnumber
     LEFT JOIN biblio      ON      biblio.biblionumber =  items.biblionumber
     LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
     LEFT JOIN itemtypes   ON itemtypes.itemtype       = $itype_link
     LEFT JOIN branches    ON  branches.branchcode     = issues.branchcode
-    WHERE (accountlines.amountoutstanding  != '0.000000')
-      AND (accountlines.accounttype         = 'FU'      )
+    WHERE (account_debits.amount_outstanding  != '0.000000')
+      AND (account_debits.type = 'FINE')
+      AND (account_debits.accruing = 1 )
       AND (issues.branchcode =  ?   )
       AND (issues.date_due  < NOW())
     ";
     my @getoverdues;
-    my $i = 0;
     my $sth;
     if ($location) {
         $sth = $dbh->prepare("$select AND items.location = ? ORDER BY borrowers.surname, borrowers.firstname");
@@ -842,12 +725,7 @@ sub GetOverduesForBranch {
         $sth->execute($branch);
     }
     while ( my $data = $sth->fetchrow_hashref ) {
-    #check if the document has already been notified
-        my $countnotify = CheckItemNotify($data->{'notify_id'}, $data->{'notify_level'}, $data->{'itemnumber'});
-        if ($countnotify eq '0') {
-            $getoverdues[$i] = $data;
-            $i++;
-        }
+        push( @getoverdues, $data );
     }
     return (@getoverdues);
 }
diff --git a/C4/Reserves.pm b/C4/Reserves.pm
index d1bca25..285ad9a 100644
--- a/C4/Reserves.pm
+++ b/C4/Reserves.pm
@@ -28,7 +28,6 @@ use C4::Biblio;
 use C4::Members;
 use C4::Items;
 use C4::Circulation;
-use C4::Accounts;
 
 # for _koha_notify_reserve
 use C4::Members::Messaging;
@@ -172,19 +171,17 @@ sub AddReserve {
         $waitingdate = $resdate;
     }
 
-    #eval {
-    # updates take place here
     if ( $fee > 0 ) {
-        my $nextacctno = &getnextacctno( $borrowernumber );
-        my $query      = qq/
-        INSERT INTO accountlines
-            (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
-        VALUES
-            (?,?,now(),?,?,'Res',?)
-    /;
-        my $usth = $dbh->prepare($query);
-        $usth->execute( $borrowernumber, $nextacctno, $fee,
-            "Reserve Charge - $title", $fee );
+        AddDebit(
+            {
+                borrowernumber => $borrowernumber,
+                itemnumber     => $checkitem,
+                amount         => $fee,
+                type           => Koha::Accounts::DebitTypes::Hold(),
+                description    => "Hold fee - $title",
+                notes          => "Record ID: $biblionumber",
+            }
+        );
     }
 
     #if ($const eq 'a'){
diff --git a/C4/SIP/ILS/Patron.pm b/C4/SIP/ILS/Patron.pm
index 5b835ca..83621d2 100644
--- a/C4/SIP/ILS/Patron.pm
+++ b/C4/SIP/ILS/Patron.pm
@@ -85,7 +85,7 @@ sub new {
         hold_ok         => ( !$debarred && !$expired ),
         card_lost       => ( $kp->{lost} || $kp->{gonenoaddress} || $flags->{LOST} ),
         claims_returned => 0,
-        fines           => $fines_amount, # GetMemberAccountRecords($kp->{borrowernumber})
+        fines           => $fines_amount,
         fees            => 0,             # currently not distinct from fines
         recall_overdue  => 0,
         items_billed    => 0,
-- 
1.7.2.5