ffzg/recall_notices.pl: added --interval and --dedup
[koha.git] / C4 / Circulation.pm
index 8bd8d85..ee9ca5f 100644 (file)
@@ -22,6 +22,7 @@ package C4::Circulation;
 use strict;
 #use warnings; FIXME - Bug 2505
 use DateTime;
 use strict;
 #use warnings; FIXME - Bug 2505
 use DateTime;
+use POSIX qw( floor );
 use Koha::DateUtils;
 use C4::Context;
 use C4::Stats;
 use Koha::DateUtils;
 use C4::Context;
 use C4::Stats;
@@ -51,13 +52,16 @@ use Koha::Patrons;
 use Koha::Patron::Debarments;
 use Koha::Database;
 use Koha::Libraries;
 use Koha::Patron::Debarments;
 use Koha::Database;
 use Koha::Libraries;
+use Koha::Account::Lines;
 use Koha::Holds;
 use Koha::RefundLostItemFeeRule;
 use Koha::RefundLostItemFeeRules;
 use Koha::Account::Lines;
 use Koha::Account::Offsets;
 use Koha::Holds;
 use Koha::RefundLostItemFeeRule;
 use Koha::RefundLostItemFeeRules;
 use Koha::Account::Lines;
 use Koha::Account::Offsets;
+use Koha::Config::SysPrefs;
+use Koha::Charges::Fees;
 use Carp;
 use Carp;
-use List::MoreUtils qw( uniq );
+use List::MoreUtils qw( uniq any );
 use Scalar::Util qw( looks_like_number );
 use Date::Calc qw(
   Today
 use Scalar::Util qw( looks_like_number );
 use Date::Calc qw(
   Today
@@ -278,10 +282,6 @@ is a reference-to-hash which may have any of the following keys:
 
 There is no item in the catalog with the given barcode. The value is C<$barcode>.
 
 
 There is no item in the catalog with the given barcode. The value is C<$barcode>.
 
-=item C<IsPermanent>
-
-The item's home branch is permanent. This doesn't prevent the item from being transferred, though. The value is the code of the item's home branch.
-
 =item C<DestinationEqualsHolding>
 
 The item is already at the branch to which it is being transferred. The transfer is nonetheless considered to have failed. The value should be ignored.
 =item C<DestinationEqualsHolding>
 
 The item is already at the branch to which it is being transferred. The transfer is nonetheless considered to have failed. The value should be ignored.
@@ -336,15 +336,6 @@ sub transferbook {
         }
     }
 
         }
     }
 
-    # if is permanent...
-    # FIXME Is this still used by someone?
-    # See other FIXME in AddReturn
-    my $library = Koha::Libraries->find($hbr);
-    if ( $library and $library->get_categories->search({'me.categorycode' => 'PE'})->count ) {
-        $messages->{'IsPermanent'} = $hbr;
-        $dotransfer = 0;
-    }
-
     # can't transfer book if is already there....
     if ( $fbr eq $tbr ) {
         $messages->{'DestinationEqualsHolding'} = 1;
     # can't transfer book if is already there....
     if ( $fbr eq $tbr ) {
         $messages->{'DestinationEqualsHolding'} = 1;
@@ -399,10 +390,20 @@ sub TooMany {
  
     # given branch, patron category, and item type, determine
     # applicable issuing rule
  
     # given branch, patron category, and item type, determine
     # applicable issuing rule
-    my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
-        {   categorycode => $cat_borrower,
+    my $maxissueqty_rule = Koha::CirculationRules->get_effective_rule(
+        {
+            categorycode => $cat_borrower,
+            itemtype     => $type,
+            branchcode   => $branch,
+            rule_name    => 'maxissueqty',
+        }
+    );
+    my $maxonsiteissueqty_rule = Koha::CirculationRules->get_effective_rule(
+        {
+            categorycode => $cat_borrower,
             itemtype     => $type,
             itemtype     => $type,
-            branchcode   => $branch
+            branchcode   => $branch,
+            rule_name    => 'maxonsiteissueqty',
         }
     );
 
         }
     );
 
@@ -410,7 +411,7 @@ sub TooMany {
     # if a rule is found and has a loan limit set, count
     # how many loans the patron already has that meet that
     # rule
     # 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($maxissueqty_rule) and defined($maxissueqty_rule->rule_value)) {
         my @bind_params;
         my $count_query = q|
             SELECT COUNT(*) AS total, COALESCE(SUM(onsite_checkout), 0) AS onsite_checkouts
         my @bind_params;
         my $count_query = q|
             SELECT COUNT(*) AS total, COALESCE(SUM(onsite_checkout), 0) AS onsite_checkouts
@@ -418,8 +419,8 @@ sub TooMany {
             JOIN items USING (itemnumber)
         |;
 
             JOIN items USING (itemnumber)
         |;
 
-        my $rule_itemtype = $issuing_rule->itemtype;
-        if ($rule_itemtype eq "*") {
+        my $rule_itemtype = $maxissueqty_rule->itemtype;
+        unless ($rule_itemtype) {
             # matching rule has the default item type, so count only
             # those existing loans that don't fall under a more
             # specific rule
             # matching rule has the default item type, so count only
             # those existing loans that don't fall under a more
             # specific rule
@@ -439,8 +440,8 @@ sub TooMany {
                                     AND   itemtype <> '*'
                                   ) ";
             }
                                     AND   itemtype <> '*'
                                   ) ";
             }
-            push @bind_params, $issuing_rule->branchcode;
-            push @bind_params, $issuing_rule->categorycode;
+            push @bind_params, $maxissueqty_rule->branchcode;
+            push @bind_params, $maxissueqty_rule->categorycode;
             push @bind_params, $cat_borrower;
         } else {
             # rule has specific item type, so count loans of that
             push @bind_params, $cat_borrower;
         } else {
             # rule has specific item type, so count loans of that
@@ -456,8 +457,8 @@ sub TooMany {
 
         $count_query .= " AND borrowernumber = ? ";
         push @bind_params, $borrower->{'borrowernumber'};
 
         $count_query .= " AND borrowernumber = ? ";
         push @bind_params, $borrower->{'borrowernumber'};
-        my $rule_branch = $issuing_rule->branchcode;
-        if ($rule_branch ne "*") {
+        my $rule_branch = $maxissueqty_rule->branchcode;
+        unless ($rule_branch) {
             if (C4::Context->preference('CircControl') eq 'PickupLibrary') {
                 $count_query .= " AND issues.branchcode = ? ";
                 push @bind_params, $branch;
             if (C4::Context->preference('CircControl') eq 'PickupLibrary') {
                 $count_query .= " AND issues.branchcode = ? ";
                 push @bind_params, $branch;
@@ -471,10 +472,10 @@ sub TooMany {
 
         my ( $checkout_count, $onsite_checkout_count ) = $dbh->selectrow_array( $count_query, {}, @bind_params );
 
 
         my ( $checkout_count, $onsite_checkout_count ) = $dbh->selectrow_array( $count_query, {}, @bind_params );
 
-        my $max_checkouts_allowed = $issuing_rule->maxissueqty;
-        my $max_onsite_checkouts_allowed = $issuing_rule->maxonsiteissueqty;
+        my $max_checkouts_allowed = $maxissueqty_rule ? $maxissueqty_rule->rule_value : undef;
+        my $max_onsite_checkouts_allowed = $maxonsiteissueqty_rule ? $maxonsiteissueqty_rule->rule_value : undef;
 
 
-        if ( $onsite_checkout ) {
+        if ( $onsite_checkout and defined $max_onsite_checkouts_allowed ) {
             if ( $onsite_checkout_count >= $max_onsite_checkouts_allowed )  {
                 return {
                     reason => 'TOO_MANY_ONSITE_CHECKOUTS',
             if ( $onsite_checkout_count >= $max_onsite_checkouts_allowed )  {
                 return {
                     reason => 'TOO_MANY_ONSITE_CHECKOUTS',
@@ -505,7 +506,7 @@ sub TooMany {
 
     # Now count total loans against the limit for the branch
     my $branch_borrower_circ_rule = GetBranchBorrowerCircRule($branch, $cat_borrower);
 
     # 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})) {
+    if (defined($branch_borrower_circ_rule->{patron_maxissueqty}) and $branch_borrower_circ_rule->{patron_maxissueqty} ne '') {
         my @bind_params = ();
         my $branch_count_query = q|
             SELECT COUNT(*) AS total, COALESCE(SUM(onsite_checkout), 0) AS onsite_checkouts
         my @bind_params = ();
         my $branch_count_query = q|
             SELECT COUNT(*) AS total, COALESCE(SUM(onsite_checkout), 0) AS onsite_checkouts
@@ -525,10 +526,10 @@ sub TooMany {
             push @bind_params, $branch;
         }
         my ( $checkout_count, $onsite_checkout_count ) = $dbh->selectrow_array( $branch_count_query, {}, @bind_params );
             push @bind_params, $branch;
         }
         my ( $checkout_count, $onsite_checkout_count ) = $dbh->selectrow_array( $branch_count_query, {}, @bind_params );
-        my $max_checkouts_allowed = $branch_borrower_circ_rule->{maxissueqty};
-        my $max_onsite_checkouts_allowed = $branch_borrower_circ_rule->{maxonsiteissueqty};
+        my $max_checkouts_allowed = $branch_borrower_circ_rule->{patron_maxissueqty};
+        my $max_onsite_checkouts_allowed = $branch_borrower_circ_rule->{patron_maxonsiteissueqty};
 
 
-        if ( $onsite_checkout ) {
+        if ( $onsite_checkout and $max_onsite_checkouts_allowed ne '' ) {
             if ( $onsite_checkout_count >= $max_onsite_checkouts_allowed )  {
                 return {
                     reason => 'TOO_MANY_ONSITE_CHECKOUTS',
             if ( $onsite_checkout_count >= $max_onsite_checkouts_allowed )  {
                 return {
                     reason => 'TOO_MANY_ONSITE_CHECKOUTS',
@@ -557,7 +558,7 @@ sub TooMany {
         }
     }
 
         }
     }
 
-    if ( not defined( $issuing_rule ) and not defined($branch_borrower_circ_rule->{maxissueqty}) ) {
+    if ( not defined( $maxissueqty_rule ) and not defined($branch_borrower_circ_rule->{patron_maxissueqty}) ) {
         return { reason => 'NO_RULE_DEFINED', max_allowed => 0 };
     }
 
         return { reason => 'NO_RULE_DEFINED', max_allowed => 0 };
     }
 
@@ -567,7 +568,7 @@ sub TooMany {
 
 =head2 CanBookBeIssued
 
 
 =head2 CanBookBeIssued
 
-  ( $issuingimpossible, $needsconfirmation, [ $alerts ] ) =  CanBookBeIssued( $borrower,
+  ( $issuingimpossible, $needsconfirmation, [ $alerts ] ) =  CanBookBeIssued( $patron,
                       $barcode, $duedate, $inprocess, $ignore_reserves, $params );
 
 Check if a book can be issued.
                       $barcode, $duedate, $inprocess, $ignore_reserves, $params );
 
 Check if a book can be issued.
@@ -580,7 +581,7 @@ data is keyed in lower case!
 
 =over 4
 
 
 =over 4
 
-=item C<$borrower> hash with borrower informations (from Koha::Patron->unblessed)
+=item C<$patron> is a Koha::Patron
 
 =item C<$barcode> is the bar code of the book being issued.
 
 
 =item C<$barcode> is the bar code of the book being issued.
 
@@ -671,7 +672,7 @@ if the borrower borrows to much things
 =cut
 
 sub CanBookBeIssued {
 =cut
 
 sub CanBookBeIssued {
-    my ( $borrower, $barcode, $duedate, $inprocess, $ignore_reserves, $params ) = @_;
+    my ( $patron, $barcode, $duedate, $inprocess, $ignore_reserves, $params ) = @_;
     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 %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.
@@ -680,18 +681,24 @@ sub CanBookBeIssued {
     my $onsite_checkout     = $params->{onsite_checkout}     || 0;
     my $override_high_holds = $params->{override_high_holds} || 0;
 
     my $onsite_checkout     = $params->{onsite_checkout}     || 0;
     my $override_high_holds = $params->{override_high_holds} || 0;
 
-    my $item = GetItem(undef, $barcode );
-    my $issue = Koha::Checkouts->find( { itemnumber => $item->{itemnumber} } );
-       my $biblioitem = GetBiblioItemData($item->{biblioitemnumber});
-       $item->{'itemtype'}=$item->{'itype'}; 
-    my $dbh             = C4::Context->dbh;
+    my $item_object = Koha::Items->find({barcode => $barcode });
 
     # MANDATORY CHECKS - unless item exists, nothing else matters
 
     # MANDATORY CHECKS - unless item exists, nothing else matters
-    unless ( $item->{barcode} ) {
+    unless ( $item_object ) {
         $issuingimpossible{UNKNOWN_BARCODE} = 1;
     }
         $issuingimpossible{UNKNOWN_BARCODE} = 1;
     }
-       return ( \%issuingimpossible, \%needsconfirmation ) if %issuingimpossible;
+    return ( \%issuingimpossible, \%needsconfirmation ) if %issuingimpossible;
+
+    my $item_unblessed = $item_object->unblessed; # Transition...
+    my $issue = $item_object->checkout;
+    my $biblio = $item_object->biblio;
+
+    my $biblioitem = $biblio->biblioitem;
+    my $effective_itemtype = $item_object->effective_itemtype;
+    my $dbh             = C4::Context->dbh;
+    my $patron_unblessed = $patron->unblessed;
 
 
+    my $circ_library = Koha::Libraries->find( _GetCircControlBranch($item_unblessed, $patron_unblessed) );
     #
     # DUE DATE is OK ? -- should already have checked.
     #
     #
     # DUE DATE is OK ? -- should already have checked.
     #
@@ -702,13 +709,22 @@ sub CanBookBeIssued {
     unless ( $duedate ) {
         my $issuedate = $now->clone();
 
     unless ( $duedate ) {
         my $issuedate = $now->clone();
 
-        my $branch = _GetCircControlBranch($item,$borrower);
-        my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'};
-        $duedate = CalcDateDue( $issuedate, $itype, $branch, $borrower );
+        my $branch = $circ_library;
+        $duedate = CalcDateDue( $issuedate, $effective_itemtype, $branch, $patron_unblessed );
 
         # Offline circ calls AddIssue directly, doesn't run through here
         #  So issuingimpossible should be ok.
     }
 
         # Offline circ calls AddIssue directly, doesn't run through here
         #  So issuingimpossible should be ok.
     }
+
+    my $fees = Koha::Charges::Fees->new(
+        {
+            patron    => $patron,
+            library   => $circ_library,
+            item      => $item_object,
+            to_date   => $duedate,
+        }
+    );
+
     if ($duedate) {
         my $today = $now->clone();
         $today->truncate( to => 'minute');
     if ($duedate) {
         my $today = $now->clone();
         $today->truncate( to => 'minute');
@@ -722,43 +738,33 @@ sub CanBookBeIssued {
     #
     # BORROWER STATUS
     #
     #
     # BORROWER STATUS
     #
-    my $patron = Koha::Patrons->find( $borrower->{borrowernumber} );
-    if ( $patron->category->category_type eq 'X' && (  $item->{barcode}  )) {
+    if ( $patron->category->category_type eq 'X' && (  $item_object->barcode  )) {
        # stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1  .
         &UpdateStats({
                      branch => C4::Context->userenv->{'branch'},
                      type => 'localuse',
        # stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1  .
         &UpdateStats({
                      branch => C4::Context->userenv->{'branch'},
                      type => 'localuse',
-                     itemnumber => $item->{'itemnumber'},
-                     itemtype => $item->{'itype'},
-                     borrowernumber => $borrower->{'borrowernumber'},
-                     ccode => $item->{'ccode'}}
+                     itemnumber => $item_object->itemnumber,
+                     itemtype => $effective_itemtype,
+                     borrowernumber => $patron->borrowernumber,
+                     ccode => $item_object->ccode}
                     );
                     );
-        ModDateLastSeen( $item->{'itemnumber'} );
+        ModDateLastSeen( $item_object->itemnumber ); # FIXME Move to Koha::Item
         return( { STATS => 1 }, {});
     }
 
         return( { STATS => 1 }, {});
     }
 
-    my $flags = C4::Members::patronflags( $borrower );
-    if ( ref $flags ) {
-        if ( $flags->{GNA} ) {
-            $issuingimpossible{GNA} = 1;
-        }
-        if ( $flags->{'LOST'} ) {
-            $issuingimpossible{CARD_LOST} = 1;
-        }
-        if ( $flags->{'DBARRED'} ) {
-            $issuingimpossible{DEBARRED} = 1;
-        }
+    if ( $patron->gonenoaddress == 1 ) {
+        $issuingimpossible{GNA} = 1;
+    }
+
+    if ( $patron->lost == 1 ) {
+        $issuingimpossible{CARD_LOST} = 1;
     }
     }
-    if ( !defined $borrower->{dateexpiry} || $borrower->{'dateexpiry'} eq '0000-00-00') {
+    if ( $patron->is_debarred ) {
+        $issuingimpossible{DEBARRED} = 1;
+    }
+
+    if ( $patron->is_expired ) {
         $issuingimpossible{EXPIRED} = 1;
         $issuingimpossible{EXPIRED} = 1;
-    } else {
-        my $expiry_dt = dt_from_string( $borrower->{dateexpiry}, 'sql', 'floating' );
-        $expiry_dt->truncate( to => 'day');
-        my $today = $now->clone()->truncate(to => 'day');
-        $today->set_time_zone( 'floating' );
-        if ( DateTime->compare($today, $expiry_dt) == 1 ) {
-            $issuingimpossible{EXPIRED} = 1;
-        }
     }
 
     #
     }
 
     #
@@ -766,8 +772,10 @@ sub CanBookBeIssued {
     #
 
     # DEBTS
     #
 
     # DEBTS
-    my ($balance, $non_issue_charges, $other_charges) =
-      C4::Members::GetMemberAccountBalance( $borrower->{'borrowernumber'} );
+    my $account = $patron->account;
+    my $balance = $account->balance;
+    my $non_issues_charges = $account->non_issues_charges;
+    my $other_charges = $balance - $non_issues_charges;
 
     my $amountlimit = C4::Context->preference("noissuescharge");
     my $allowfineoverride = C4::Context->preference("AllowFineOverride");
 
     my $amountlimit = C4::Context->preference("noissuescharge");
     my $allowfineoverride = C4::Context->preference("AllowFineOverride");
@@ -777,12 +785,10 @@ sub CanBookBeIssued {
     my $no_issues_charge_guarantees = C4::Context->preference("NoIssuesChargeGuarantees");
     $no_issues_charge_guarantees = undef unless looks_like_number( $no_issues_charge_guarantees );
     if ( defined $no_issues_charge_guarantees ) {
     my $no_issues_charge_guarantees = C4::Context->preference("NoIssuesChargeGuarantees");
     $no_issues_charge_guarantees = undef unless looks_like_number( $no_issues_charge_guarantees );
     if ( defined $no_issues_charge_guarantees ) {
-        my $p = Koha::Patrons->find( $borrower->{borrowernumber} );
-        my @guarantees = $p->guarantees();
+        my @guarantees = $patron->guarantees();
         my $guarantees_non_issues_charges;
         foreach my $g ( @guarantees ) {
         my $guarantees_non_issues_charges;
         foreach my $g ( @guarantees ) {
-            my ( $b, $n, $o ) = C4::Members::GetMemberAccountBalance( $g->id );
-            $guarantees_non_issues_charges += $n;
+            $guarantees_non_issues_charges += $g->account->non_issues_charges;
         }
 
         if ( $guarantees_non_issues_charges > $no_issues_charge_guarantees && !$inprocess && !$allowfineoverride) {
         }
 
         if ( $guarantees_non_issues_charges > $no_issues_charge_guarantees && !$inprocess && !$allowfineoverride) {
@@ -795,21 +801,21 @@ sub CanBookBeIssued {
     }
 
     if ( C4::Context->preference("IssuingInProcess") ) {
     }
 
     if ( C4::Context->preference("IssuingInProcess") ) {
-        if ( $non_issue_charges > $amountlimit && !$inprocess && !$allowfineoverride) {
-            $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges );
-        } 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 ) {
-            $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
+        if ( $non_issues_charges > $amountlimit && !$inprocess && !$allowfineoverride) {
+            $issuingimpossible{DEBT} = $non_issues_charges;
+        } elsif ( $non_issues_charges > $amountlimit && !$inprocess && $allowfineoverride) {
+            $needsconfirmation{DEBT} = $non_issues_charges;
+        } elsif ( $allfinesneedoverride && $non_issues_charges > 0 && $non_issues_charges <= $amountlimit && !$inprocess ) {
+            $needsconfirmation{DEBT} = $non_issues_charges;
         }
     }
     else {
         }
     }
     else {
-        if ( $non_issue_charges > $amountlimit && $allowfineoverride ) {
-            $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
-        } elsif ( $non_issue_charges > $amountlimit && !$allowfineoverride) {
-            $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges );
-        } elsif ( $non_issue_charges > 0 && $allfinesneedoverride ) {
-            $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
+        if ( $non_issues_charges > $amountlimit && $allowfineoverride ) {
+            $needsconfirmation{DEBT} = $non_issues_charges;
+        } elsif ( $non_issues_charges > $amountlimit && !$allowfineoverride) {
+            $issuingimpossible{DEBT} = $non_issues_charges;
+        } elsif ( $non_issues_charges > 0 && $allfinesneedoverride ) {
+            $needsconfirmation{DEBT} = $non_issues_charges;
         }
     }
 
         }
     }
 
@@ -817,7 +823,9 @@ sub CanBookBeIssued {
         $alerts{OTHER_CHARGES} = sprintf( "%.2f", $other_charges );
     }
 
         $alerts{OTHER_CHARGES} = sprintf( "%.2f", $other_charges );
     }
 
-    $patron = Koha::Patrons->find( $borrower->{borrowernumber} );
+    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
+    $patron_unblessed = $patron->unblessed;
+
     if ( my $debarred_date = $patron->is_debarred ) {
          # patron has accrued fine days or has a restriction. $count is a date
         if ($debarred_date eq '9999-12-31') {
     if ( my $debarred_date = $patron->is_debarred ) {
          # patron has accrued fine days or has a restriction. $count is a date
         if ($debarred_date eq '9999-12-31') {
@@ -839,7 +847,7 @@ sub CanBookBeIssued {
     #
     # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER
     #
     #
     # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER
     #
-    if ( $issue && $issue->borrowernumber eq $borrower->{'borrowernumber'} ){
+    if ( $issue && $issue->borrowernumber eq $patron->borrowernumber ){
 
         # Already issued to current borrower.
         # If it is an on-site checkout if it can be switched to a normal checkout
 
         # Already issued to current borrower.
         # If it is an on-site checkout if it can be switched to a normal checkout
@@ -850,8 +858,8 @@ sub CanBookBeIssued {
             $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
         } else {
             my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
             $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
         } else {
             my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
-                $borrower->{'borrowernumber'},
-                $item->{'itemnumber'},
+                $patron->borrowernumber,
+                $item_object->itemnumber,
             );
             if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
                 if ( $renewerror eq 'onsite_checkout' ) {
             );
             if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
                 if ( $renewerror eq 'onsite_checkout' ) {
@@ -872,7 +880,7 @@ sub CanBookBeIssued {
 
         my $patron = Koha::Patrons->find( $issue->borrowernumber );
 
 
         my $patron = Koha::Patrons->find( $issue->borrowernumber );
 
-        my ( $can_be_returned, $message ) = CanBookBeReturned( $item, C4::Context->userenv->{branch} );
+        my ( $can_be_returned, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
 
         unless ( $can_be_returned ) {
             $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
 
         unless ( $can_be_returned ) {
             $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
@@ -892,8 +900,8 @@ sub CanBookBeIssued {
           C4::Context->preference('SwitchOnSiteCheckouts')
       and $issue
       and $issue->onsite_checkout
           C4::Context->preference('SwitchOnSiteCheckouts')
       and $issue
       and $issue->onsite_checkout
-      and $issue->borrowernumber == $borrower->{'borrowernumber'} ? 1 : 0 );
-    my $toomany = TooMany( $borrower, $item->{biblionumber}, $item, { onsite_checkout => $onsite_checkout, switch_onsite_checkout => $switch_onsite_checkout, } );
+      and $issue->borrowernumber == $patron->borrowernumber ? 1 : 0 );
+    my $toomany = TooMany( $patron_unblessed, $item_object->biblionumber, $item_unblessed, { onsite_checkout => $onsite_checkout, switch_onsite_checkout => $switch_onsite_checkout, } );
     # if TooMany max_allowed returns 0 the user doesn't have permission to check out this book
     if ( $toomany && not exists $needsconfirmation{RENEW_ISSUE} ) {
         if ( $toomany->{max_allowed} == 0 ) {
     # if TooMany max_allowed returns 0 the user doesn't have permission to check out this book
     if ( $toomany && not exists $needsconfirmation{RENEW_ISSUE} ) {
         if ( $toomany->{max_allowed} == 0 ) {
@@ -913,22 +921,22 @@ sub CanBookBeIssued {
     #
     # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
     #
     #
     # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
     #
-    $patron = Koha::Patrons->find($borrower->{borrowernumber});
+    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
     my $wants_check = $patron->wants_check_for_previous_checkout;
     $needsconfirmation{PREVISSUE} = 1
     my $wants_check = $patron->wants_check_for_previous_checkout;
     $needsconfirmation{PREVISSUE} = 1
-        if ($wants_check and $patron->do_check_for_previous_checkout($item));
+        if ($wants_check and $patron->do_check_for_previous_checkout($item_unblessed));
 
     #
     # ITEM CHECKING
     #
 
     #
     # ITEM CHECKING
     #
-    if ( $item->{'notforloan'} )
+    if ( $item_object->notforloan )
     {
         if(!C4::Context->preference("AllowNotForLoanOverride")){
             $issuingimpossible{NOT_FOR_LOAN} = 1;
     {
         if(!C4::Context->preference("AllowNotForLoanOverride")){
             $issuingimpossible{NOT_FOR_LOAN} = 1;
-            $issuingimpossible{item_notforloan} = $item->{'notforloan'};
+            $issuingimpossible{item_notforloan} = $item_object->notforloan;
         }else{
             $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
         }else{
             $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
-            $needsconfirmation{item_notforloan} = $item->{'notforloan'};
+            $needsconfirmation{item_notforloan} = $item_object->notforloan;
         }
     }
     else {
         }
     }
     else {
@@ -936,39 +944,42 @@ sub CanBookBeIssued {
         if (C4::Context->preference('item-level_itypes')){
             # this should probably be a subroutine
             my $sth = $dbh->prepare("SELECT notforloan FROM itemtypes WHERE itemtype = ?");
         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'});
+            $sth->execute($effective_itemtype);
             my $notforloan=$sth->fetchrow_hashref();
             if ($notforloan->{'notforloan'}) {
                 if (!C4::Context->preference("AllowNotForLoanOverride")) {
                     $issuingimpossible{NOT_FOR_LOAN} = 1;
             my $notforloan=$sth->fetchrow_hashref();
             if ($notforloan->{'notforloan'}) {
                 if (!C4::Context->preference("AllowNotForLoanOverride")) {
                     $issuingimpossible{NOT_FOR_LOAN} = 1;
-                    $issuingimpossible{itemtype_notforloan} = $item->{'itype'};
+                    $issuingimpossible{itemtype_notforloan} = $effective_itemtype;
                 } else {
                     $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
                 } else {
                     $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
-                    $needsconfirmation{itemtype_notforloan} = $item->{'itype'};
+                    $needsconfirmation{itemtype_notforloan} = $effective_itemtype;
                 }
             }
         }
                 }
             }
         }
-        elsif ($biblioitem->{'notforloan'} == 1){
-            if (!C4::Context->preference("AllowNotForLoanOverride")) {
-                $issuingimpossible{NOT_FOR_LOAN} = 1;
-                $issuingimpossible{itemtype_notforloan} = $biblioitem->{'itemtype'};
-            } else {
-                $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
-                $needsconfirmation{itemtype_notforloan} = $biblioitem->{'itemtype'};
+        else {
+            my $itemtype = Koha::ItemTypes->find($biblioitem->itemtype);
+            if ( $itemtype and $itemtype->notforloan == 1){
+                if (!C4::Context->preference("AllowNotForLoanOverride")) {
+                    $issuingimpossible{NOT_FOR_LOAN} = 1;
+                    $issuingimpossible{itemtype_notforloan} = $effective_itemtype;
+                } else {
+                    $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
+                    $needsconfirmation{itemtype_notforloan} = $effective_itemtype;
+                }
             }
         }
     }
             }
         }
     }
-    if ( $item->{'withdrawn'} && $item->{'withdrawn'} > 0 )
+    if ( $item_object->withdrawn && $item_object->withdrawn > 0 )
     {
         $issuingimpossible{WTHDRAWN} = 1;
     }
     {
         $issuingimpossible{WTHDRAWN} = 1;
     }
-    if (   $item->{'restricted'}
-        && $item->{'restricted'} == 1 )
+    if (   $item_object->restricted
+        && $item_object->restricted == 1 )
     {
         $issuingimpossible{RESTRICTED} = 1;
     }
     {
         $issuingimpossible{RESTRICTED} = 1;
     }
-    if ( $item->{'itemlost'} && C4::Context->preference("IssueLostItem") ne 'nothing' ) {
-        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $item->{itemlost} });
+    if ( $item_object->itemlost && C4::Context->preference("IssueLostItem") ne 'nothing' ) {
+        my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $item_object->itemlost });
         my $code = $av->count ? $av->next->lib : '';
         $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' );
         $alerts{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' );
         my $code = $av->count ? $av->next->lib : '';
         $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' );
         $alerts{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' );
@@ -976,12 +987,13 @@ sub CanBookBeIssued {
     if ( C4::Context->preference("IndependentBranches") ) {
         my $userenv = C4::Context->userenv;
         unless ( C4::Context->IsSuperLibrarian() ) {
     if ( C4::Context->preference("IndependentBranches") ) {
         my $userenv = C4::Context->userenv;
         unless ( C4::Context->IsSuperLibrarian() ) {
-            if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} ){
+            my $HomeOrHoldingBranch = C4::Context->preference("HomeOrHoldingBranch");
+            if ( $item_object->$HomeOrHoldingBranch ne $userenv->{branch} ){
                 $issuingimpossible{ITEMNOTSAMEBRANCH} = 1;
                 $issuingimpossible{ITEMNOTSAMEBRANCH} = 1;
-                $issuingimpossible{'itemhomebranch'} = $item->{C4::Context->preference("HomeOrHoldingBranch")};
+                $issuingimpossible{'itemhomebranch'} = $item_object->$HomeOrHoldingBranch;
             }
             }
-            $needsconfirmation{BORRNOTSAMEBRANCH} = $borrower->{'branchcode'}
-              if ( $borrower->{'branchcode'} ne $userenv->{branch} );
+            $needsconfirmation{BORRNOTSAMEBRANCH} = $patron->branchcode
+              if ( $patron->branchcode ne $userenv->{branch} );
         }
     }
     #
         }
     }
     #
@@ -990,7 +1002,9 @@ sub CanBookBeIssued {
     my $rentalConfirmation = C4::Context->preference("RentalFeesCheckoutConfirmation");
 
     if ( $rentalConfirmation ){
     my $rentalConfirmation = C4::Context->preference("RentalFeesCheckoutConfirmation");
 
     if ( $rentalConfirmation ){
-        my ($rentalCharge) = GetIssuingCharges( $item->{'itemnumber'}, $borrower->{'borrowernumber'} );
+        my ($rentalCharge) = GetIssuingCharges( $item_object->itemnumber, $patron->borrowernumber );
+        my $itemtype = Koha::ItemTypes->find( $item_object->itype ); # GetItem sets effective itemtype
+        $rentalCharge += $fees->accumulate_rentalcharge({ from => dt_from_string(), to => $duedate });
         if ( $rentalCharge > 0 ){
             $needsconfirmation{RENTALCHARGE} = $rentalCharge;
         }
         if ( $rentalCharge > 0 ){
             $needsconfirmation{RENTALCHARGE} = $rentalCharge;
         }
@@ -998,10 +1012,10 @@ sub CanBookBeIssued {
 
     unless ( $ignore_reserves ) {
         # See if the item is on reserve.
 
     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_object->itemnumber );
         if ($restype) {
             my $resbor = $res->{'borrowernumber'};
         if ($restype) {
             my $resbor = $res->{'borrowernumber'};
-            if ( $resbor ne $borrower->{'borrowernumber'} ) {
+            if ( $resbor ne $patron->borrowernumber ) {
                 my $patron = Koha::Patrons->find( $resbor );
                 if ( $restype eq "Waiting" )
                 {
                 my $patron = Koha::Patrons->find( $resbor );
                 if ( $restype eq "Waiting" )
                 {
@@ -1030,8 +1044,8 @@ sub CanBookBeIssued {
     }
 
     ## CHECK AGE RESTRICTION
     }
 
     ## CHECK AGE RESTRICTION
-    my $agerestriction  = $biblioitem->{'agerestriction'};
-    my ($restriction_age, $daysToAgeRestriction) = GetAgeRestriction( $agerestriction, $borrower );
+    my $agerestriction  = $biblioitem->agerestriction;
+    my ($restriction_age, $daysToAgeRestriction) = GetAgeRestriction( $agerestriction, $patron->unblessed );
     if ( $daysToAgeRestriction && $daysToAgeRestriction > 0 ) {
         if ( C4::Context->preference('AgeRestrictionOverride') ) {
             $needsconfirmation{AGE_RESTRICTION} = "$agerestriction";
     if ( $daysToAgeRestriction && $daysToAgeRestriction > 0 ) {
         if ( C4::Context->preference('AgeRestrictionOverride') ) {
             $needsconfirmation{AGE_RESTRICTION} = "$agerestriction";
@@ -1043,21 +1057,21 @@ sub CanBookBeIssued {
 
     ## check for high holds decreasing loan period
     if ( C4::Context->preference('decreaseLoanHighHolds') ) {
 
     ## check for high holds decreasing loan period
     if ( C4::Context->preference('decreaseLoanHighHolds') ) {
-        my $check = checkHighHolds( $item, $borrower );
+        my $check = checkHighHolds( $item_unblessed, $patron_unblessed );
 
         if ( $check->{exceeded} ) {
             if ($override_high_holds) {
                 $alerts{HIGHHOLDS} = {
                     num_holds  => $check->{outstanding},
                     duration   => $check->{duration},
 
         if ( $check->{exceeded} ) {
             if ($override_high_holds) {
                 $alerts{HIGHHOLDS} = {
                     num_holds  => $check->{outstanding},
                     duration   => $check->{duration},
-                    returndate => output_pref( $check->{due_date} ),
+                    returndate => output_pref( { dt => dt_from_string($check->{due_date}), dateformat => 'iso', timeformat => '24hr' }),
                 };
             }
             else {
                 $needsconfirmation{HIGHHOLDS} = {
                     num_holds  => $check->{outstanding},
                     duration   => $check->{duration},
                 };
             }
             else {
                 $needsconfirmation{HIGHHOLDS} = {
                     num_holds  => $check->{outstanding},
                     duration   => $check->{duration},
-                    returndate => output_pref( $check->{due_date} ),
+                    returndate => output_pref( { dt => dt_from_string($check->{due_date}), dateformat => 'iso', timeformat => '24hr' }),
                 };
             }
         }
                 };
             }
         }
@@ -1072,13 +1086,14 @@ sub CanBookBeIssued {
     ) {
         # Check if borrower has already issued an item from the same biblio
         # Only if it's not a subscription
     ) {
         # Check if borrower has already issued an item from the same biblio
         # Only if it's not a subscription
-        my $biblionumber = $item->{biblionumber};
+        my $biblionumber = $item_object->biblionumber;
         require C4::Serials;
         my $is_a_subscription = C4::Serials::CountSubscriptionFromBiblionumber($biblionumber);
         unless ($is_a_subscription) {
         require C4::Serials;
         my $is_a_subscription = C4::Serials::CountSubscriptionFromBiblionumber($biblionumber);
         unless ($is_a_subscription) {
+            # FIXME Should be $patron->checkouts($args);
             my $checkouts = Koha::Checkouts->search(
                 {
             my $checkouts = Koha::Checkouts->search(
                 {
-                    borrowernumber => $borrower->{borrowernumber},
+                    borrowernumber => $patron->borrowernumber,
                     biblionumber   => $biblionumber,
                 },
                 {
                     biblionumber   => $biblionumber,
                 },
                 {
@@ -1104,7 +1119,7 @@ Check whether the item can be returned to the provided branch
 
 =over 4
 
 
 =over 4
 
-=item C<$item> is a hash of item information as returned from GetItem
+=item C<$item> is a hash of item information as returned Koha::Items->find->unblessed (Temporary, should be a Koha::Item instead)
 
 =item C<$branch> is the branchcode where the return is taking place
 
 
 =item C<$branch> is the branchcode where the return is taking place
 
@@ -1198,7 +1213,7 @@ sub checkHighHolds {
             }
 
             # Remove any items that are not holdable for this patron
             }
 
             # Remove any items that are not holdable for this patron
-            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber ) eq 'OK' } @items;
+            @items = grep { CanItemBeReserved( $borrower->{borrowernumber}, $_->itemnumber )->{status} eq 'OK' } @items;
 
             my $items_count = scalar @items;
 
 
             my $items_count = scalar @items;
 
@@ -1302,40 +1317,58 @@ sub AddIssue {
     # Stop here if the patron or barcode doesn't exist
     if ( $borrower && $barcode && $barcodecheck ) {
         # find which item we issue
     # Stop here if the patron or barcode doesn't exist
     if ( $borrower && $barcode && $barcodecheck ) {
         # find which item we issue
-        my $item = GetItem( '', $barcode )
+        my $item_object = Koha::Items->find({ barcode => $barcode })
           or return;    # if we don't get an Item, abort.
           or return;    # if we don't get an Item, abort.
-        my $item_object = Koha::Items->find( { barcode => $barcode } );
+        my $item_unblessed = $item_object->unblessed;
 
 
-        my $branch = _GetCircControlBranch( $item, $borrower );
+        my $branch = _GetCircControlBranch( $item_unblessed, $borrower );
 
         # get actual issuing if there is one
 
         # get actual issuing if there is one
-        my $actualissue = Koha::Checkouts->find( { itemnumber => $item->{itemnumber} } );
+        my $actualissue = $item_object->checkout;
 
         # check if we just renew the issue.
         if ( $actualissue and $actualissue->borrowernumber eq $borrower->{'borrowernumber'}
                 and not $switch_onsite_checkout ) {
             $datedue = AddRenewal(
                 $borrower->{'borrowernumber'},
 
         # check if we just renew the issue.
         if ( $actualissue and $actualissue->borrowernumber eq $borrower->{'borrowernumber'}
                 and not $switch_onsite_checkout ) {
             $datedue = AddRenewal(
                 $borrower->{'borrowernumber'},
-                $item->{'itemnumber'},
+                $item_object->itemnumber,
                 $branch,
                 $datedue,
                 $issuedate,    # here interpreted as the renewal date
             );
         }
         else {
                 $branch,
                 $datedue,
                 $issuedate,    # here interpreted as the renewal date
             );
         }
         else {
+            unless ($datedue) {
+                my $itype = $item_object->effective_itemtype;
+                $datedue = CalcDateDue( $issuedate, $itype, $branch, $borrower );
+
+            }
+            $datedue->truncate( to => 'minute' );
+
+            my $patron = Koha::Patrons->find( $borrower );
+            my $library = Koha::Libraries->find( $branch );
+            my $fees = Koha::Charges::Fees->new(
+                {
+                    patron    => $patron,
+                    library   => $library,
+                    item      => $item_object,
+                    to_date   => $datedue,
+                }
+            );
+
             # it's NOT a renewal
             if ( $actualissue and not $switch_onsite_checkout ) {
                 # 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
             # it's NOT a renewal
             if ( $actualissue and not $switch_onsite_checkout ) {
                 # 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
-                my ( $allowed, $message ) = CanBookBeReturned( $item, C4::Context->userenv->{branch} );
+                my ( $allowed, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
                 return unless $allowed;
                 return unless $allowed;
-                AddReturn( $item->{'barcode'}, C4::Context->userenv->{'branch'} );
+                AddReturn( $item_object->barcode, C4::Context->userenv->{'branch'} );
             }
 
             }
 
-            MoveReserve( $item->{'itemnumber'}, $borrower->{'borrowernumber'}, $cancelreserve );
+            C4::Reserves::MoveReserve( $item_object->itemnumber, $borrower->{'borrowernumber'}, $cancelreserve );
 
             # Starting process for transfer job (checking transfert and validate it if we have one)
 
             # Starting process for transfer job (checking transfert and validate it if we have one)
-            my ($datesent) = GetTransfers( $item->{'itemnumber'} );
+            my ($datesent) = GetTransfers( $item_object->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(
             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(
@@ -1346,14 +1379,14 @@ sub AddIssue {
                     WHERE itemnumber= ? AND datearrived IS NULL"
                 );
                 $sth->execute( C4::Context->userenv->{'branch'},
                     WHERE itemnumber= ? AND datearrived IS NULL"
                 );
                 $sth->execute( C4::Context->userenv->{'branch'},
-                    $item->{'itemnumber'} );
+                    $item_object->itemnumber );
             }
 
             # If automatic renewal wasn't selected while issuing, set the value according to the issuing rule.
             unless ($auto_renew) {
                 my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
                     {   categorycode => $borrower->{categorycode},
             }
 
             # If automatic renewal wasn't selected while issuing, set the value according to the issuing rule.
             unless ($auto_renew) {
                 my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
                     {   categorycode => $borrower->{categorycode},
-                        itemtype     => $item->{itype},
+                        itemtype     => $item_object->effective_itemtype,
                         branchcode   => $branch
                     }
                 );
                         branchcode   => $branch
                     }
                 );
@@ -1369,62 +1402,83 @@ sub AddIssue {
             }
             $datedue->truncate( to => 'minute' );
 
             }
             $datedue->truncate( to => 'minute' );
 
-            $issue = Koha::Database->new()->schema()->resultset('Issue')->update_or_create(
-                {
-                    borrowernumber => $borrower->{'borrowernumber'},
-                    itemnumber     => $item->{'itemnumber'},
-                    issuedate      => $issuedate->strftime('%Y-%m-%d %H:%M:%S'),
-                    date_due       => $datedue->strftime('%Y-%m-%d %H:%M:%S'),
-                    branchcode     => C4::Context->userenv->{'branch'},
-                    onsite_checkout => $onsite_checkout,
-                    auto_renew      => $auto_renew ? 1 : 0
-                }
-              );
+            my $issue_attributes = {
+                borrowernumber  => $borrower->{'borrowernumber'},
+                issuedate       => $issuedate->strftime('%Y-%m-%d %H:%M:%S'),
+                date_due        => $datedue->strftime('%Y-%m-%d %H:%M:%S'),
+                branchcode      => C4::Context->userenv->{'branch'},
+                onsite_checkout => $onsite_checkout,
+                auto_renew      => $auto_renew ? 1 : 0,
+            };
+
+            $issue = Koha::Checkouts->find( { itemnumber => $item_object->itemnumber } );
+            if ($issue) {
+                $issue->set($issue_attributes)->store;
+            }
+            else {
+                $issue = Koha::Checkout->new(
+                    {
+                        itemnumber => $item_object->itemnumber,
+                        %$issue_attributes,
+                    }
+                )->store;
+            }
 
             if ( C4::Context->preference('ReturnToShelvingCart') ) {
                 # ReturnToShelvingCart is on, anything issued should be taken off the cart.
 
             if ( C4::Context->preference('ReturnToShelvingCart') ) {
                 # ReturnToShelvingCart is on, anything issued should be taken off the cart.
-                CartToShelf( $item->{'itemnumber'} );
+                CartToShelf( $item_object->itemnumber );
             }
             }
-            $item->{'issues'}++;
+
             if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) {
             if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) {
-                UpdateTotalIssues( $item->{'biblionumber'}, 1 );
+                UpdateTotalIssues( $item_object->biblionumber, 1 );
             }
 
             ## If item was lost, it has now been found, reverse any list item charges if necessary.
             }
 
             ## If item was lost, it has now been found, reverse any list item charges if necessary.
-            if ( $item->{'itemlost'} ) {
+            if ( $item_object->itemlost ) {
                 if (
                     Koha::RefundLostItemFeeRules->should_refund(
                         {
                             current_branch      => C4::Context->userenv->{branch},
                 if (
                     Koha::RefundLostItemFeeRules->should_refund(
                         {
                             current_branch      => C4::Context->userenv->{branch},
-                            item_home_branch    => $item->{homebranch},
-                            item_holding_branch => $item->{holdingbranch}
+                            item_home_branch    => $item_object->homebranch,
+                            item_holding_branch => $item_object->holdingbranch,
                         }
                     )
                   )
                 {
                         }
                     )
                   )
                 {
-                    _FixAccountForLostAndReturned( $item->{'itemnumber'}, undef,
-                        $item->{'barcode'} );
+                    _FixAccountForLostAndReturned( $item_object->itemnumber, undef,
+                        $item_object->barcode );
                 }
             }
 
             ModItem(
                 {
                 }
             }
 
             ModItem(
                 {
-                    issues        => $item->{'issues'},
+                    issues        => $item_object->issues + 1,
                     holdingbranch => C4::Context->userenv->{'branch'},
                     itemlost      => 0,
                     onloan        => $datedue->ymd(),
                     datelastborrowed => DateTime->now( time_zone => C4::Context->tz() )->ymd(),
                 },
                     holdingbranch => C4::Context->userenv->{'branch'},
                     itemlost      => 0,
                     onloan        => $datedue->ymd(),
                     datelastborrowed => DateTime->now( time_zone => C4::Context->tz() )->ymd(),
                 },
-                $item->{'biblionumber'},
-                $item->{'itemnumber'}
+                $item_object->biblionumber,
+                $item_object->itemnumber,
+                { log_action => 0 }
             );
             );
-            ModDateLastSeen( $item->{'itemnumber'} );
+            ModDateLastSeen( $item_object->itemnumber );
 
 
-           # If it costs to borrow this book, charge it to the patron's account.
-            my ( $charge, $itemtype ) = GetIssuingCharges( $item->{'itemnumber'}, $borrower->{'borrowernumber'} );
+            # If it costs to borrow this book, charge it to the patron's account.
+            my ( $charge, $itemtype ) = GetIssuingCharges( $item_object->itemnumber, $borrower->{'borrowernumber'} );
             if ( $charge > 0 ) {
             if ( $charge > 0 ) {
-                AddIssuingCharge( $item->{'itemnumber'}, $borrower->{'borrowernumber'}, $charge );
-                $item->{'charge'} = $charge;
+                my $description = "Rental";
+                AddIssuingCharge( $issue, $charge, $description );
+            }
+
+            my $itemtype_object = Koha::ItemTypes->find( $item_object->effective_itemtype );
+            if ( $itemtype_object ) {
+                my $accumulate_charge = $fees->accumulate_rentalcharge();
+                if ( $accumulate_charge > 0 ) {
+                    AddIssuingCharge( $issue, $accumulate_charge, 'Daily rental' ) if $accumulate_charge > 0;
+                    $charge += $accumulate_charge;
+                    $item_unblessed->{charge} = $charge;
+                }
             }
 
             # Record the fact that this book was issued.
             }
 
             # Record the fact that this book was issued.
@@ -1434,10 +1488,11 @@ sub AddIssue {
                     type => ( $onsite_checkout ? 'onsite_checkout' : 'issue' ),
                     amount         => $charge,
                     other          => ( $sipmode ? "SIP-$sipmode" : '' ),
                     type => ( $onsite_checkout ? 'onsite_checkout' : 'issue' ),
                     amount         => $charge,
                     other          => ( $sipmode ? "SIP-$sipmode" : '' ),
-                    itemnumber     => $item->{'itemnumber'},
-                    itemtype       => $item->{'itype'},
+                    itemnumber     => $item_object->itemnumber,
+                    itemtype       => $item_object->effective_itemtype,
+                    location       => $item_object->location,
                     borrowernumber => $borrower->{'borrowernumber'},
                     borrowernumber => $borrower->{'borrowernumber'},
-                    ccode          => $item->{'ccode'}
+                    ccode          => $item_object->ccode,
                 }
             );
 
                 }
             );
 
@@ -1446,14 +1501,14 @@ sub AddIssue {
             my %conditions        = (
                 branchcode   => $branch,
                 categorycode => $borrower->{categorycode},
             my %conditions        = (
                 branchcode   => $branch,
                 categorycode => $borrower->{categorycode},
-                item_type    => $item->{itype},
+                item_type    => $item_object->effective_itemtype,
                 notification => 'CHECKOUT',
             );
             if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
                 SendCirculationAlert(
                     {
                         type     => 'CHECKOUT',
                 notification => 'CHECKOUT',
             );
             if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
                 SendCirculationAlert(
                     {
                         type     => 'CHECKOUT',
-                        item     => $item,
+                        item     => $item_object->unblessed,
                         borrower => $borrower,
                         branch   => $branch,
                     }
                         borrower => $borrower,
                         branch   => $branch,
                     }
@@ -1462,7 +1517,7 @@ sub AddIssue {
             logaction(
                 "CIRCULATION", "ISSUE",
                 $borrower->{'borrowernumber'},
             logaction(
                 "CIRCULATION", "ISSUE",
                 $borrower->{'borrowernumber'},
-                $item->{'itemnumber'}
+                $item_object->itemnumber,
             ) if C4::Context->preference("IssueLog");
         }
     }
             ) if C4::Context->preference("IssueLog");
         }
     }
@@ -1479,6 +1534,13 @@ Get loan length for an itemtype, a borrower type and a branch
 
 sub GetLoanLength {
     my ( $borrowertype, $itemtype, $branchcode ) = @_;
 
 sub GetLoanLength {
     my ( $borrowertype, $itemtype, $branchcode ) = @_;
+
+               # FIXME FFZG -- submit bug to koha
+               if ( ref($branchcode) ) {
+                       Carp::cluck("$branchcode");
+                       $branchcode = 'FFZG';
+                       warn "FIXME branchcode = $branchcode";
+               }
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare(qq{
         SELECT issuelength, lengthunit, renewalperiod
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare(qq{
         SELECT issuelength, lengthunit, renewalperiod
@@ -1578,28 +1640,25 @@ Retrieves circulation rule attributes that apply to the given
 branch and patron category, regardless of item type.  
 The return value is a hashref containing the following key:
 
 branch and patron category, regardless of item type.  
 The return value is a hashref containing the following key:
 
-maxissueqty - maximum number of loans that a
+patron_maxissueqty - maximum number of loans that a
 patron of the given category can have at the given
 branch.  If the value is undef, no limit.
 
 patron of the given category can have at the given
 branch.  If the value is undef, no limit.
 
-maxonsiteissueqty - maximum of on-site checkouts that a
+patron_maxonsiteissueqty - maximum of on-site checkouts that a
 patron of the given category can have at the given
 branch.  If the value is undef, no limit.
 
 patron of the given category can have at the given
 branch.  If the value is undef, no limit.
 
-This will first check for a specific branch and
-category match from branch_borrower_circ_rules. 
-
-If no rule is found, it will then check default_branch_circ_rules
-(same branch, default category).  If no rule is found,
-it will then check default_borrower_circ_rules (default 
-branch, same category), then failing that, default_circ_rules
-(default branch, default category).
+This will check for different branch/category combinations in the following order:
+branch and category
+branch only
+category only
+default branch and category
 
 If no rule has been found in the database, it will default to
 the buillt in rule:
 
 
 If no rule has been found in the database, it will default to
 the buillt in rule:
 
-maxissueqty - undef
-maxonsiteissueqty - undef
+patron_maxissueqty - undef
+patron_maxonsiteissueqty - undef
 
 C<$branchcode> and C<$categorycode> should contain the
 literal branch code and patron category code, respectively - no
 
 C<$branchcode> and C<$categorycode> should contain the
 literal branch code and patron category code, respectively - no
@@ -1610,44 +1669,27 @@ wildcards.
 sub GetBranchBorrowerCircRule {
     my ( $branchcode, $categorycode ) = @_;
 
 sub GetBranchBorrowerCircRule {
     my ( $branchcode, $categorycode ) = @_;
 
-    my $rules;
-    my $dbh = C4::Context->dbh();
-    $rules = $dbh->selectrow_hashref( q|
-        SELECT maxissueqty, maxonsiteissueqty
-        FROM branch_borrower_circ_rules
-        WHERE branchcode = ?
-        AND   categorycode = ?
-    |, {}, $branchcode, $categorycode ) ;
-    return $rules if $rules;
-
-    # try same branch, default borrower category
-    $rules = $dbh->selectrow_hashref( q|
-        SELECT maxissueqty, maxonsiteissueqty
-        FROM default_branch_circ_rules
-        WHERE branchcode = ?
-    |, {}, $branchcode ) ;
-    return $rules if $rules;
-
-    # try default branch, same borrower category
-    $rules = $dbh->selectrow_hashref( q|
-        SELECT maxissueqty, maxonsiteissueqty
-        FROM default_borrower_circ_rules
-        WHERE categorycode = ?
-    |, {}, $categorycode ) ;
-    return $rules if $rules;
-
-    # try default branch, default borrower category
-    $rules = $dbh->selectrow_hashref( q|
-        SELECT maxissueqty, maxonsiteissueqty
-        FROM default_circ_rules
-    |, {} );
-    return $rules if $rules;
-
-    # built-in default circulation rule
-    return {
-        maxissueqty => undef,
-        maxonsiteissueqty => undef,
+    # Initialize default values
+    my $rules = {
+        patron_maxissueqty       => undef,
+        patron_maxonsiteissueqty => undef,
     };
     };
+
+    # Search for rules!
+    foreach my $rule_name (qw( patron_maxissueqty patron_maxonsiteissueqty )) {
+        my $rule = Koha::CirculationRules->get_effective_rule(
+            {
+                categorycode => $categorycode,
+                itemtype     => undef,
+                branchcode   => $branchcode,
+                rule_name    => $rule_name,
+            }
+        );
+
+        $rules->{$rule_name} = $rule->rule_value if defined $rule;
+    }
+
+    return $rules;
 }
 
 =head2 GetBranchItemRule
 }
 
 =head2 GetBranchItemRule
@@ -1724,7 +1766,7 @@ sub GetBranchItemRule {
 =head2 AddReturn
 
   ($doreturn, $messages, $iteminformation, $borrower) =
 =head2 AddReturn
 
   ($doreturn, $messages, $iteminformation, $borrower) =
-      &AddReturn( $barcode, $branch [,$exemptfine] [,$dropbox] [,$returndate] );
+      &AddReturn( $barcode, $branch [,$exemptfine] [,$returndate] );
 
 Returns a book.
 
 
 Returns a book.
 
@@ -1737,12 +1779,6 @@ Returns a book.
 =item C<$exemptfine> indicates that overdue charges for the item will be
 removed. Optional.
 
 =item C<$exemptfine> indicates that overdue charges for the item will be
 removed. Optional.
 
-=item C<$dropbox> indicates that the check-in date is assumed to be
-yesterday, or the last non-holiday as defined in C4::Calendar .  If
-overdue charges are applied and C<$dropbox> is true, the last charge
-will be removed.  This assumes that the fines accrual script has run
-for _today_. Optional.
-
 =item C<$return_date> allows the default return date to be overridden
 by the given return date. Optional.
 
 =item C<$return_date> allows the default return date to be overridden
 by the given return date. Optional.
 
@@ -1765,12 +1801,6 @@ No item with this barcode exists. The value is C<$barcode>.
 
 The book is not currently on loan. The value is C<$barcode>.
 
 
 The book is not currently on loan. The value is C<$barcode>.
 
-=item C<IsPermanent>
-
-The book's home branch is a permanent collection. If you have borrowed
-this book, you are not allowed to return it. The value is the code for
-the book's home branch.
-
 =item C<withdrawn>
 
 This book has been withdrawn/cancelled. The value should be ignored.
 =item C<withdrawn>
 
 This book has been withdrawn/cancelled. The value should be ignored.
@@ -1807,13 +1837,14 @@ patron who last borrowed the book.
 =cut
 
 sub AddReturn {
 =cut
 
 sub AddReturn {
-    my ( $barcode, $branch, $exemptfine, $dropbox, $return_date, $dropboxdate ) = @_;
+    my ( $barcode, $branch, $exemptfine, $return_date ) = @_;
 
     if ($branch and not Koha::Libraries->find($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
 
     if ($branch and not Koha::Libraries->find($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
+    $return_date //= dt_from_string();
     my $messages;
     my $patron;
     my $doreturn       = 1;
     my $messages;
     my $patron;
     my $doreturn       = 1;
@@ -1821,21 +1852,22 @@ sub AddReturn {
     my $stat_type = 'return';
 
     # get information on item
     my $stat_type = 'return';
 
     # get information on item
-    my $item = GetItem( undef, $barcode );
+    my $item = Koha::Items->find({ barcode => $barcode });
     unless ($item) {
         return ( 0, { BadBarcode => $barcode } );    # no barcode means no item or borrower.  bail out.
     }
 
     unless ($item) {
         return ( 0, { BadBarcode => $barcode } );    # no barcode means no item or borrower.  bail out.
     }
 
-    my $itemnumber = $item->{ itemnumber };
-    my $itemtype = $item->{itype}; # GetItem called effective_itemtype
+    my $itemnumber = $item->itemnumber;
+    my $itemtype = $item->effective_itemtype;
 
 
-    my $issue  = Koha::Checkouts->find( { itemnumber => $itemnumber } );
+    my $issue  = $item->checkout;
     if ( $issue ) {
     if ( $issue ) {
-        $patron = Koha::Patrons->find( $issue->borrowernumber )
+        $patron = $issue->patron
             or die "Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existent borrowernumber '" . $issue->borrowernumber . "'\n"
                 . Dumper($issue->unblessed) . "\n";
     } else {
         $messages->{'NotIssued'} = $barcode;
             or die "Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existent borrowernumber '" . $issue->borrowernumber . "'\n"
                 . Dumper($issue->unblessed) . "\n";
     } else {
         $messages->{'NotIssued'} = $barcode;
+        ModItem({ onloan => undef }, $item->biblionumber, $item->itemnumber) if defined $item->onloan;
         # 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.
         # 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.
@@ -1846,21 +1878,22 @@ sub AddReturn {
         }
     }
 
         }
     }
 
-    if ( $item->{'location'} eq 'PROC' ) {
+    my $item_unblessed = $item->unblessed;
+    if ( $item->location eq 'PROC' ) {
         if ( C4::Context->preference("InProcessingToShelvingCart") ) {
         if ( C4::Context->preference("InProcessingToShelvingCart") ) {
-            $item->{'location'} = 'CART';
+            $item_unblessed->{location} = 'CART';
         }
         else {
         }
         else {
-            $item->{location} = $item->{permanent_location};
+            $item_unblessed->{location} = $item->permanent_location;
         }
 
         }
 
-        ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} );
+        ModItem( $item_unblessed, $item->biblionumber, $item->itemnumber, { log_action => 0 } );
     }
 
         # full item data, but no borrowernumber or checkout info (no issue)
     }
 
         # full item data, but no borrowernumber or checkout info (no issue)
-    my $hbr = GetBranchItemRule($item->{'homebranch'}, $item->{'itype'})->{'returnbranch'} || "homebranch";
+    my $hbr = GetBranchItemRule($item->homebranch, $itemtype)->{'returnbranch'} || "homebranch";
         # get the proper branch to which to return the item
         # get the proper branch to which to return the item
-    my $returnbranch = $item->{$hbr} || $branch ;
+    my $returnbranch = $hbr ne 'noreturn' ? $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 = $patron ? $patron->borrowernumber : undef;    # we don't know if we had a borrower or not
         # if $hbr was "noreturn" or any other non-item table value, then it should 'float' (i.e. stay at this branch)
 
     my $borrowernumber = $patron ? $patron->borrowernumber : undef;    # we don't know if we had a borrower or not
@@ -1876,27 +1909,17 @@ sub AddReturn {
         }
         else {
             foreach my $key ( keys %$rules ) {
         }
         else {
             foreach my $key ( keys %$rules ) {
-                if ( $item->{notforloan} eq $key ) {
-                    $messages->{'NotForLoanStatusUpdated'} = { from => $item->{notforloan}, to => $rules->{$key} };
-                    ModItem( { notforloan => $rules->{$key} }, undef, $itemnumber );
+                if ( $item->notforloan eq $key ) {
+                    $messages->{'NotForLoanStatusUpdated'} = { from => $item->notforloan, to => $rules->{$key} };
+                    ModItem( { notforloan => $rules->{$key} }, undef, $itemnumber, { log_action => 0 } );
                     last;
                 }
             }
         }
     }
 
                     last;
                 }
             }
         }
     }
 
-
-    # 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 ( $returnbranch ) {
-        my $library = Koha::Libraries->find($returnbranch);
-        if ( $library and $library->get_categories->search({'me.categorycode' => 'PE'})->count ) {
-            $messages->{'IsPermanent'} = $returnbranch;
-        }
-    }
-
     # check if the return is allowed at this branch
     # check if the return is allowed at this branch
-    my ($returnallowed, $message) = CanBookBeReturned($item, $branch);
+    my ($returnallowed, $message) = CanBookBeReturned($item_unblessed, $branch);
     unless ($returnallowed){
         $messages->{'Wrongbranch'} = {
             Wrongbranch => $branch,
     unless ($returnallowed){
         $messages->{'Wrongbranch'} = {
             Wrongbranch => $branch,
@@ -1906,38 +1929,29 @@ sub AddReturn {
         return ( $doreturn, $messages, $issue, $patron_unblessed);
     }
 
         return ( $doreturn, $messages, $issue, $patron_unblessed);
     }
 
-    if ( $item->{'withdrawn'} ) { # book has been cancelled
+    if ( $item->withdrawn ) { # book has been cancelled
         $messages->{'withdrawn'} = 1;
         $doreturn = 0 if C4::Context->preference("BlockReturnOfWithdrawnItems");
     }
 
         $messages->{'withdrawn'} = 1;
         $doreturn = 0 if C4::Context->preference("BlockReturnOfWithdrawnItems");
     }
 
-    # case of a return of document (deal with issues and holdingbranch)
-    my $today = DateTime->now( time_zone => C4::Context->tz() );
+    if ( $item->itemlost and C4::Context->preference("BlockReturnOfLostItems") ) {
+        $doreturn = 0;
+    }
 
 
+    # case of a return of document (deal with issues and holdingbranch)
     if ($doreturn) {
         my $is_overdue;
         die "The item is not issed and cannot be returned" unless $issue; # Just in case...
         $patron or warn "AddReturn without current borrower";
     if ($doreturn) {
         my $is_overdue;
         die "The item is not issed and cannot be returned" unless $issue; # Just in case...
         $patron 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,$patron_unblessed);
-            $is_overdue = $issue->is_overdue( $dropboxdate );
-        } else {
-            $is_overdue = $issue->is_overdue;
-        }
+        $is_overdue = $issue->is_overdue( $return_date );
 
         if ($patron) {
             eval {
 
         if ($patron) {
             eval {
-                MarkIssueReturned( $borrowernumber, $item->{'itemnumber'},
-                    $circControlBranch, $return_date, $patron->privacy );
+                MarkIssueReturned( $borrowernumber, $item->itemnumber, $return_date, $patron->privacy );
             };
             unless ( $@ ) {
             };
             unless ( $@ ) {
-                if ( ( C4::Context->preference('CalculateFinesOnReturn') && $is_overdue ) || $return_date ) {
-                    _CalculateAndUpdateFine( { issue => $issue, item => $item, borrower => $patron_unblessed, return_date => $return_date } );
+                if ( C4::Context->preference('CalculateFinesOnReturn') && $is_overdue ) {
+                    _CalculateAndUpdateFine( { issue => $issue, item => $item_unblessed, borrower => $patron_unblessed, return_date => $return_date } );
                 }
             } else {
                 carp "The checkin for the following issue failed, Please go to the about page, section 'data corrupted' to know how to fix this problem ($@)" . Dumper( $issue->unblessed );
                 }
             } else {
                 carp "The checkin for the following issue failed, Please go to the about page, section 'data corrupted' to know how to fix this problem ($@)" . Dumper( $issue->unblessed );
@@ -1950,57 +1964,59 @@ sub AddReturn {
 
         }
 
 
         }
 
-        ModItem({ onloan => undef }, $item->{biblionumber}, $item->{'itemnumber'});
+        ModItem( { onloan => undef }, $item->biblionumber, $item->itemnumber, { log_action => 0 } );
     }
 
     # 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
     }
 
     # 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
-    my $item_holding_branch = $item->{ holdingbranch };
-    if ($item->{'holdingbranch'} ne $branch) {
-        UpdateHoldingbranch($branch, $item->{'itemnumber'});
-        $item->{'holdingbranch'} = $branch; # update item data holdingbranch too
+    my $item_holding_branch = $item->holdingbranch;
+    if ($item->holdingbranch ne $branch) {
+        UpdateHoldingbranch($branch, $item->itemnumber);
+        $item_unblessed->{'holdingbranch'} = $branch; # update item data holdingbranch too # FIXME I guess this is for the _debar_user_on_return call later
     }
     }
-    ModDateLastSeen( $item->{'itemnumber'} );
+
+    my $leave_item_lost = C4::Context->preference("BlockReturnOfLostItems") ? 1 : 0;
+    ModDateLastSeen( $item->itemnumber, $leave_item_lost );
 
     # check if we have a transfer for this document
 
     # 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
-    my $is_in_rotating_collection = C4::RotatingCollections::isItemInAnyCollection( $item->{'itemnumber'} );
+    my $is_in_rotating_collection = C4::RotatingCollections::isItemInAnyCollection( $item->itemnumber );
     if ($datesent) {
         if ( $tobranch eq $branch ) {
             my $sth = C4::Context->dbh->prepare(
                 "UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL"
             );
     if ($datesent) {
         if ( $tobranch eq $branch ) {
             my $sth = C4::Context->dbh->prepare(
                 "UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL"
             );
-            $sth->execute( $item->{'itemnumber'} );
+            $sth->execute( $item->itemnumber );
             # if we have a reservation with valid transfer, we can set it's status to 'W'
             # 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');
+            ShelfToCart( $item->itemnumber ) if ( C4::Context->preference("ReturnToShelvingCart") );
+            C4::Reserves::ModReserveStatus($item->itemnumber, 'W');
         } else {
             $messages->{'WrongTransfer'}     = $tobranch;
         } else {
             $messages->{'WrongTransfer'}     = $tobranch;
-            $messages->{'WrongTransferItem'} = $item->{'itemnumber'};
+            $messages->{'WrongTransferItem'} = $item->itemnumber;
         }
         $validTransfert = 1;
     } else {
         }
         $validTransfert = 1;
     } else {
-        ShelfToCart( $item->{'itemnumber'} ) if ( C4::Context->preference("ReturnToShelvingCart") );
+        ShelfToCart( $item->itemnumber ) if ( C4::Context->preference("ReturnToShelvingCart") );
     }
 
     # fix up the accounts.....
     }
 
     # fix up the accounts.....
-    if ( $item->{'itemlost'} ) {
+    if ( $item->itemlost ) {
         $messages->{'WasLost'} = 1;
         $messages->{'WasLost'} = 1;
-
-        if ( $item->{'itemlost'} ) {
+        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
             if (
                 Koha::RefundLostItemFeeRules->should_refund(
                     {
                         current_branch      => C4::Context->userenv->{branch},
             if (
                 Koha::RefundLostItemFeeRules->should_refund(
                     {
                         current_branch      => C4::Context->userenv->{branch},
-                        item_home_branch    => $item->{homebranch},
+                        item_home_branch    => $item->homebranch,
                         item_holding_branch => $item_holding_branch
                     }
                 )
               )
             {
                         item_holding_branch => $item_holding_branch
                     }
                 )
               )
             {
-                _FixAccountForLostAndReturned( $item->{'itemnumber'}, $borrowernumber, $barcode );
+                _FixAccountForLostAndReturned( $item->itemnumber,
+                    $borrowernumber, $barcode );
                 $messages->{'LostItemFeeRefunded'} = 1;
             }
         }
                 $messages->{'LostItemFeeRefunded'} = 1;
             }
         }
@@ -2008,13 +2024,12 @@ sub AddReturn {
 
     # fix up the overdues in accounts...
     if ($borrowernumber) {
 
     # 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 );
+        defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->itemnumber...) failed!";  # zero is OK, check defined
 
         if ( $issue and $issue->is_overdue ) {
         # fix fine days
 
         if ( $issue and $issue->is_overdue ) {
         # fix fine days
-            $today = $dropboxdate if $dropbox;
-            my ($debardate,$reminder) = _debar_user_on_return( $patron_unblessed, $item, dt_from_string($issue->date_due), $today );
+            my ($debardate,$reminder) = _debar_user_on_return( $patron_unblessed, $item_unblessed, dt_from_string($issue->date_due), $return_date );
             if ($reminder){
                 $messages->{'PrevDebarred'} = $debardate;
             } else {
             if ($reminder){
                 $messages->{'PrevDebarred'} = $debardate;
             } else {
@@ -2027,7 +2042,7 @@ sub AddReturn {
              } else {
                   my $borrower_debar_dt = dt_from_string( $patron->debarred );
                   $borrower_debar_dt->truncate(to => 'day');
              } else {
                   my $borrower_debar_dt = dt_from_string( $patron->debarred );
                   $borrower_debar_dt->truncate(to => 'day');
-                  my $today_dt = $today->clone()->truncate(to => 'day');
+                  my $today_dt = $return_date->clone()->truncate(to => 'day');
                   if ( DateTime->compare( $borrower_debar_dt, $today_dt ) != -1 ) {
                       $messages->{'PrevDebarred'} = $patron->debarred;
                   }
                   if ( DateTime->compare( $borrower_debar_dt, $today_dt ) != -1 ) {
                       $messages->{'PrevDebarred'} = $patron->debarred;
                   }
@@ -2039,7 +2054,7 @@ sub AddReturn {
     # 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
     # 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'} );
+    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
     if ($resfound) {
           $resrec->{'ResFound'} = $resfound;
         $messages->{'ResFound'} = $resrec;
     if ($resfound) {
           $resrec->{'ResFound'} = $resfound;
         $messages->{'ResFound'} = $resrec;
@@ -2052,7 +2067,7 @@ sub AddReturn {
         itemnumber     => $itemnumber,
         itemtype       => $itemtype,
         borrowernumber => $borrowernumber,
         itemnumber     => $itemnumber,
         itemtype       => $itemtype,
         borrowernumber => $borrowernumber,
-        ccode          => $item->{ ccode }
+        ccode          => $item->ccode,
     });
 
     # Send a check-in slip. # NOTE: borrower may be undef. Do not try to send messages then.
     });
 
     # Send a check-in slip. # NOTE: borrower may be undef. Do not try to send messages then.
@@ -2061,19 +2076,19 @@ sub AddReturn {
         my %conditions = (
             branchcode   => $branch,
             categorycode => $patron->categorycode,
         my %conditions = (
             branchcode   => $branch,
             categorycode => $patron->categorycode,
-            item_type    => $item->{itype},
+            item_type    => $itemtype,
             notification => 'CHECKIN',
         );
         if ($doreturn && $circulation_alert->is_enabled_for(\%conditions)) {
             SendCirculationAlert({
                 type     => 'CHECKIN',
             notification => 'CHECKIN',
         );
         if ($doreturn && $circulation_alert->is_enabled_for(\%conditions)) {
             SendCirculationAlert({
                 type     => 'CHECKIN',
-                item     => $item,
+                item     => $item_unblessed,
                 borrower => $patron->unblessed,
                 branch   => $branch,
             });
         }
 
                 borrower => $patron->unblessed,
                 branch   => $branch,
             });
         }
 
-        logaction("CIRCULATION", "RETURN", $borrowernumber, $item->{'itemnumber'})
+        logaction("CIRCULATION", "RETURN", $borrowernumber, $item->itemnumber)
             if C4::Context->preference("ReturnLog");
         }
 
             if C4::Context->preference("ReturnLog");
         }
 
@@ -2089,13 +2104,14 @@ sub AddReturn {
 
     # Transfer to returnbranch if Automatic transfer set or append message NeedsTransfer
     if (!$is_in_rotating_collection && ($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $returnbranch) and not $messages->{'WrongTransfer'}){
 
     # Transfer to returnbranch if Automatic transfer set or append message NeedsTransfer
     if (!$is_in_rotating_collection && ($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $returnbranch) and not $messages->{'WrongTransfer'}){
+        my $BranchTransferLimitsType = C4::Context->preference("BranchTransferLimitsType");
         if  (C4::Context->preference("AutomaticItemReturn"    ) or
             (C4::Context->preference("UseBranchTransferLimits") and
         if  (C4::Context->preference("AutomaticItemReturn"    ) or
             (C4::Context->preference("UseBranchTransferLimits") and
-             ! IsBranchTransferAllowed($branch, $returnbranch, $item->{C4::Context->preference("BranchTransferLimitsType")} )
+             ! IsBranchTransferAllowed($branch, $returnbranch, $item->$BranchTransferLimitsType )
            )) {
            )) {
-            $debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'},$branch, $returnbranch;
-            $debug and warn "item: " . Dumper($item);
-            ModItemTransfer($item->{'itemnumber'}, $branch, $returnbranch);
+            $debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->itemnumber,$branch, $returnbranch;
+            $debug and warn "item: " . Dumper($item_unblessed);
+            ModItemTransfer($item->itemnumber, $branch, $returnbranch);
             $messages->{'WasTransfered'} = 1;
         } else {
             $messages->{'NeedsTransfer'} = $returnbranch;
             $messages->{'WasTransfered'} = 1;
         } else {
             $messages->{'NeedsTransfer'} = $returnbranch;
@@ -2107,30 +2123,26 @@ sub AddReturn {
 
 =head2 MarkIssueReturned
 
 
 =head2 MarkIssueReturned
 
-  MarkIssueReturned($borrowernumber, $itemnumber, $dropbox_branch, $returndate, $privacy);
+  MarkIssueReturned($borrowernumber, $itemnumber, $returndate, $privacy);
 
 Unconditionally marks an issue as being returned by
 moving the C<issues> row to C<old_issues> and
 
 Unconditionally marks an issue as being returned by
 moving the C<issues> row to C<old_issues> and
-setting C<returndate> to the current date, or
-the last non-holiday date of the branccode specified in
-C<dropbox_branch> .  Assumes you've already checked that 
-it's safe to do this, i.e. last non-holiday > issuedate.
+setting C<returndate> to the current date.
 
 if C<$returndate> is specified (in iso format), it is used as the date
 
 if C<$returndate> is specified (in iso format), it is used as the date
-of the return. It is ignored when a dropbox_branch is passed in.
+of the return.
 
 C<$privacy> contains the privacy parameter. If the patron has set privacy to 2,
 the old_issue is immediately anonymised
 
 Ideally, this function would be internal to C<C4::Circulation>,
 
 C<$privacy> contains the privacy parameter. If the patron has set privacy to 2,
 the old_issue is immediately anonymised
 
 Ideally, this function would be internal to C<C4::Circulation>,
-not exported, but it is currently needed by one 
-routine in C<C4::Accounts>.
+not exported, but it is currently used in misc/cronjobs/longoverdue.pl
+and offline_circ/process_koc.pl.
 
 =cut
 
 sub MarkIssueReturned {
 
 =cut
 
 sub MarkIssueReturned {
-    my ( $borrowernumber, $itemnumber, $dropbox_branch, $returndate, $privacy ) = @_;
-
+    my ( $borrowernumber, $itemnumber, $returndate, $privacy ) = @_;
 
     # Retrieve the issue
     my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } ) or return;
 
     # Retrieve the issue
     my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } ) or return;
@@ -2146,47 +2158,32 @@ sub MarkIssueReturned {
         die "Fatal error: the patron ($borrowernumber) has requested their circulation history be anonymized on check-in, but the AnonymousPatron system preference is empty or not set correctly."
             unless Koha::Patrons->find( $anonymouspatron );
     }
         die "Fatal error: the patron ($borrowernumber) has requested their circulation history be anonymized on check-in, but the AnonymousPatron system preference is empty or not set correctly."
             unless Koha::Patrons->find( $anonymouspatron );
     }
-    my $database = Koha::Database->new();
-    my $schema   = $database->schema;
-    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 );
-        $query .= ' ? ';
-        push @bind, $dropboxdate->strftime('%Y-%m-%d %H:%M');
-    } elsif ($returndate) {
-        $query .= ' ? ';
-        push @bind, $returndate;
-    } else {
-        $query .= ' now() ';
-    }
-    $query .= ' WHERE issue_id = ?';
-    push @bind, $issue_id;
+    my $schema = Koha::Database->schema;
 
     # FIXME Improve the return value and handle it from callers
     $schema->txn_do(sub {
 
 
     # FIXME Improve the return value and handle it from callers
     $schema->txn_do(sub {
 
-        # Update the returndate
-        $dbh->do( $query, undef, @bind );
-
-        # We just updated the returndate, so we need to refetch $issue
-        $issue->discard_changes;
+        # Update the returndate value
+        if ( $returndate ) {
+            $issue->returndate( $returndate )->store->discard_changes; # update and refetch
+        }
+        else {
+            $issue->returndate( \'NOW()' )->store->discard_changes; # update and refetch
+        }
 
         # Create the old_issues entry
         my $old_checkout = Koha::Old::Checkout->new($issue->unblessed)->store;
 
         # anonymise patron checkout immediately if $privacy set to 2 and AnonymousPatron is set to a valid borrowernumber
         if ( $privacy == 2) {
 
         # Create the old_issues entry
         my $old_checkout = Koha::Old::Checkout->new($issue->unblessed)->store;
 
         # anonymise patron checkout immediately if $privacy set to 2 and AnonymousPatron is set to a valid borrowernumber
         if ( $privacy == 2) {
-            $dbh->do(q|UPDATE old_issues SET borrowernumber=? WHERE issue_id = ?|, undef, $anonymouspatron, $old_checkout->issue_id);
+            $old_checkout->borrowernumber($anonymouspatron)->store;
         }
 
         # And finally delete the issue
         $issue->delete;
 
         }
 
         # And finally delete the issue
         $issue->delete;
 
-        ModItem( { 'onloan' => undef }, undef, $itemnumber );
+        ModItem( { 'onloan' => undef }, undef, $itemnumber, { log_action => 0 } );
 
         if ( C4::Context->preference('StoreLastBorrower') ) {
             my $item = Koha::Items->find( $itemnumber );
 
         if ( C4::Context->preference('StoreLastBorrower') ) {
             my $item = Koha::Items->find( $itemnumber );
@@ -2200,7 +2197,7 @@ sub MarkIssueReturned {
 
 =head2 _debar_user_on_return
 
 
 =head2 _debar_user_on_return
 
-    _debar_user_on_return($borrower, $item, $datedue, today);
+    _debar_user_on_return($borrower, $item, $datedue, $returndate);
 
 C<$borrower> borrower hashref
 
 
 C<$borrower> borrower hashref
 
@@ -2208,7 +2205,7 @@ C<$item> item hashref
 
 C<$datedue> date due DateTime object
 
 
 C<$datedue> date due DateTime object
 
-C<$return_date> DateTime object representing the return time
+C<$returndate> DateTime object representing the return time
 
 Internal function, called only by AddReturn that calculates and updates
  the user fine days, and debars them if necessary.
 
 Internal function, called only by AddReturn that calculates and updates
  the user fine days, and debars them if necessary.
@@ -2221,6 +2218,7 @@ sub _debar_user_on_return {
     my ( $borrower, $item, $dt_due, $return_date ) = @_;
 
     my $branchcode = _GetCircControlBranch( $item, $borrower );
     my ( $borrower, $item, $dt_due, $return_date ) = @_;
 
     my $branchcode = _GetCircControlBranch( $item, $borrower );
+    $return_date //= dt_from_string();
 
     my $circcontrol = C4::Context->preference('CircControl');
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
 
     my $circcontrol = C4::Context->preference('CircControl');
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
@@ -2267,8 +2265,25 @@ sub _debar_user_on_return {
                 }
             }
 
                 }
             }
 
-            my $new_debar_dt =
-              $return_date->clone()->add_duration( $suspension_days );
+            if ( $issuing_rule->suspension_chargeperiod > 1 ) {
+                # No need to / 1 and do not consider / 0
+                $suspension_days = DateTime::Duration->new(
+                    days => floor( $suspension_days->in_units('days') / $issuing_rule->suspension_chargeperiod )
+                );
+            }
+
+            my $new_debar_dt;
+            # Use the calendar or not to calculate the debarment date
+            if ( C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed' ) {
+                my $calendar = Koha::Calendar->new(
+                    branchcode => $branchcode,
+                    days_mode  => 'Calendar'
+                );
+                $new_debar_dt = $calendar->addDate( $return_date, $suspension_days );
+            }
+            else {
+                $new_debar_dt = $return_date->clone()->add_duration($suspension_days);
+            }
 
             Koha::Patron::Debarments::AddUniqueDebarment({
                 borrowernumber => $borrower->{borrowernumber},
 
             Koha::Patron::Debarments::AddUniqueDebarment({
                 borrowernumber => $borrower->{borrowernumber},
@@ -2293,31 +2308,28 @@ sub _debar_user_on_return {
 
 =head2 _FixOverduesOnReturn
 
 
 =head2 _FixOverduesOnReturn
 
-   &_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode);
+   &_FixOverduesOnReturn($borrowernumber, $itemnumber, $exemptfine);
 
 
-C<$brn> borrowernumber
+C<$borrowernumber> borrowernumber
 
 
-C<$itm> itemnumber
+C<$itemnumber> itemnumber
 
 C<$exemptfine> BOOL -- remove overdue charge associated with this issue. 
 
 C<$exemptfine> BOOL -- remove overdue charge associated with this issue. 
-C<$dropboxmode> BOOL -- remove lastincrement on overdue charge associated with this issue.
 
 
-Internal function, called only by AddReturn
+Internal function
 
 =cut
 
 sub _FixOverduesOnReturn {
 
 =cut
 
 sub _FixOverduesOnReturn {
-    my ($borrowernumber, $item);
-    unless ($borrowernumber = shift) {
+    my ( $borrowernumber, $item, $exemptfine ) = @_;
+    unless( $borrowernumber ) {
         warn "_FixOverduesOnReturn() not supplied valid borrowernumber";
         return;
     }
         warn "_FixOverduesOnReturn() not supplied valid borrowernumber";
         return;
     }
-    unless ($item = shift) {
+    unless( $item ) {
         warn "_FixOverduesOnReturn() not supplied valid itemnumber";
         return;
     }
         warn "_FixOverduesOnReturn() not supplied valid itemnumber";
         return;
     }
-    my ($exemptfine, $dropbox) = @_;
-    my $dbh = C4::Context->dbh;
 
     # check for overdue fine
     my $accountline = Koha::Account::Lines->search(
 
     # check for overdue fine
     my $accountline = Koha::Account::Lines->search(
@@ -2332,7 +2344,6 @@ sub _FixOverduesOnReturn {
     )->next();
     return 0 unless $accountline;    # no warning, there's just nothing to fix
 
     )->next();
     return 0 unless $accountline;    # no warning, there's just nothing to fix
 
-    my $uquery;
     if ($exemptfine) {
         my $amountoutstanding = $accountline->amountoutstanding;
 
     if ($exemptfine) {
         my $amountoutstanding = $accountline->amountoutstanding;
 
@@ -2345,35 +2356,11 @@ sub _FixOverduesOnReturn {
                 type => 'Forgiven',
                 amount => $amountoutstanding * -1,
             }
                 type => 'Forgiven',
                 amount => $amountoutstanding * -1,
             }
-        );
+        )->store();
 
         if (C4::Context->preference("FinesLog")) {
             &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
         }
 
         if (C4::Context->preference("FinesLog")) {
             &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
         }
-    } elsif ($dropbox && $accountline->lastincrement) {
-        my $outstanding = $accountline->amountoutstanding - $accountline->lastincrement;
-        my $amt = $accountline->amount - $accountline->lastincrement;
-
-        Koha::Account::Offset->new(
-            {
-                debit_id => $accountline->id,
-                type => 'Dropbox',
-                amount => $accountline->lastincrement * -1,
-            }
-        );
-
-        if ( C4::Context->preference("FinesLog") ) {
-            &logaction( "FINES", 'MODIFY', $borrowernumber,
-                "Dropbox adjustment $amt, item $item" );
-        }
-
-        $accountline->accounttype('F');
-
-        if ( $outstanding >= 0 && $amt >= 0 ) {
-            $accountline->amount($amt);
-            $accountline->amountoutstanding($outstanding);
-        }
-
     } else {
         $accountline->accounttype('F');
     }
     } else {
         $accountline->accounttype('F');
     }
@@ -2396,38 +2383,68 @@ sub _FixAccountForLostAndReturned {
     my $borrowernumber = @_ ? shift : undef;
     my $item_id        = @_ ? shift : $itemnumber;  # Send the barcode if you want that logged in the description
 
     my $borrowernumber = @_ ? shift : undef;
     my $item_id        = @_ ? shift : $itemnumber;  # Send the barcode if you want that logged in the description
 
+    my $credit;
+
     # check for charge made for lost book
     # check for charge made for lost book
-    my $accountline = Koha::Account::Lines->search(
+    my $accountlines = Koha::Account::Lines->search(
         {
             itemnumber  => $itemnumber,
             accounttype => { -in => [ 'L', 'Rep', 'W' ] },
         },
         {
         {
             itemnumber  => $itemnumber,
             accounttype => { -in => [ 'L', 'Rep', 'W' ] },
         },
         {
-            order_by => { -desc => [ 'date', 'accountno' ] }
+            order_by => { -desc => [ 'date', 'accountlines_id' ] }
         }
         }
-    )->next();
+    );
 
 
-    return unless $accountline;
-    return if $accountline->accounttype eq 'W';    # Written off
+    return unless $accountlines->count > 0;
+    my $accountline     = $accountlines->next;
+    my $total_to_refund = 0;
+    my $account = Koha::Patrons->find( $accountline->borrowernumber )->account;
+
+    # Use cases
+    if ( $accountline->amount > $accountline->amountoutstanding ) {
+        # some amount has been cancelled. collect the offsets that are not writeoffs
+        # this works because the only way to subtract from this kind of a debt is
+        # using the UI buttons 'Pay' and 'Write off'
+        my $credits_offsets = Koha::Account::Offsets->search({
+            debit_id  => $accountline->id,
+            credit_id => { '!=' => undef }, # it is not the debit itself
+            type      => { '!=' => 'Writeoff' },
+            amount    => { '<'  => 0 } # credits are negative on the DB
+        });
+
+        $total_to_refund = ( $credits_offsets->count > 0 )
+                            ? $credits_offsets->total * -1 # credits are negative on the DB
+                            : 0;
+    }
 
 
-    $accountline->accounttype('LR');
-    $accountline->store();
+    my $credit_total = $accountline->amountoutstanding + $total_to_refund;
 
 
-    my $account = Koha::Account->new( { patron_id => $accountline->borrowernumber } );
-    my $credit_id = $account->pay(
-        {
-            amount       => $accountline->amount,
-            description  => "Item Returned " . $item_id,
-            account_type => 'CR',
-            offset_type  => 'Lost Item Return',
-            accounlines  => [$accountline],
+    if ( $credit_total > 0 ) {
+        my $branchcode = C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
+        $credit = $account->add_credit(
+            {   amount      => $credit_total,
+                description => 'Item Returned ' . $item_id,
+                type        => 'lost_item_return',
+                library_id  => $branchcode
+            }
+        );
 
 
-        }
-    );
+        # TODO: ->apply should just accept the accountline
+        $credit->apply( { debits => $accountlines->reset } );
+    }
+
+    # Manually set the accounttype
+    $accountline->discard_changes->accounttype('LR');
+    $accountline->store;
+
+    ModItem( { paidfor => '' }, undef, $itemnumber, { log_action => 0 } );
 
 
-    ModItem( { paidfor => '' }, undef, $itemnumber );
+    if ( defined $account and C4::Context->preference('AccountAutoReconcile') ) {
+        $account->reconcile_balance;
+    }
 
 
-    return $credit_id;
+    return ($credit) ? $credit->id : undef;
 }
 
 =head2 _GetCircControlBranch
 }
 
 =head2 _GetCircControlBranch
@@ -2546,12 +2563,15 @@ sub GetUpcomingDueIssues {
     my $dbh = C4::Context->dbh;
 
     my $statement = <<END_SQL;
     my $dbh = C4::Context->dbh;
 
     my $statement = <<END_SQL;
-SELECT issues.*, items.itype as itemtype, items.homebranch, TO_DAYS( date_due )-TO_DAYS( NOW() ) as days_until_due, branches.branchemail
-FROM issues 
-LEFT JOIN items USING (itemnumber)
-LEFT OUTER JOIN branches USING (branchcode)
-WHERE returndate is NULL
-HAVING days_until_due >= 0 AND days_until_due <= ?
+SELECT *
+FROM (
+    SELECT issues.*, items.itype as itemtype, items.homebranch, TO_DAYS( date_due )-TO_DAYS( NOW() ) as days_until_due, branches.branchemail
+    FROM issues
+    LEFT JOIN items USING (itemnumber)
+    LEFT OUTER JOIN branches USING (branchcode)
+    WHERE returndate is NULL
+) tmp
+WHERE days_until_due >= 0 AND days_until_due <= ?
 END_SQL
 
     my @bind_parameters = ( $params->{'days_in_advance'} );
 END_SQL
 
     my @bind_parameters = ( $params->{'days_in_advance'} );
@@ -2593,13 +2613,12 @@ sub CanBookBeRenewed {
     my $dbh    = C4::Context->dbh;
     my $renews = 1;
 
     my $dbh    = C4::Context->dbh;
     my $renews = 1;
 
-    my $item      = GetItem($itemnumber)      or return ( 0, 'no_item' );
-    my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } ) or return ( 0, 'no_checkout' );
+    my $item      = Koha::Items->find($itemnumber)      or return ( 0, 'no_item' );
+    my $issue = $item->checkout or return ( 0, 'no_checkout' );
     return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
     return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
+    return ( 0, 'item_denied_renewal') if _item_denied_renewal({ item => $item });
 
 
-    $borrowernumber ||= $issue->borrowernumber;
-    my $patron = Koha::Patrons->find( $borrowernumber )
-      or return;
+    my $patron = $issue->patron or return;
 
     my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber);
 
 
     my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber);
 
@@ -2649,7 +2668,7 @@ sub CanBookBeRenewed {
             my @reservable;
             my %borrowers;
             ITEM: foreach my $i (@itemnumbers) {
             my @reservable;
             my %borrowers;
             ITEM: foreach my $i (@itemnumbers) {
-                my $item = GetItem($i);
+                my $item = Koha::Items->find($i)->unblessed;
                 next if IsItemOnHoldAndFound($i);
                 for my $b (@borrowernumbers) {
                     my $borr = $borrowers{$b} //= Koha::Patrons->find( $b )->unblessed;
                 next if IsItemOnHoldAndFound($i);
                 for my $b (@borrowernumbers) {
                     my $borr = $borrowers{$b} //= Koha::Patrons->find( $b )->unblessed;
@@ -2670,10 +2689,10 @@ sub CanBookBeRenewed {
 
     return ( 1, undef ) if $override_limit;
 
 
     return ( 1, undef ) if $override_limit;
 
-    my $branchcode = _GetCircControlBranch( $item, $patron->unblessed );
+    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
-            itemtype     => $item->{itype},
+            itemtype     => $item->effective_itemtype,
             branchcode   => $branchcode
         }
     );
             branchcode   => $branchcode
         }
     );
@@ -2694,6 +2713,11 @@ sub CanBookBeRenewed {
     }
 
     if ( $issue->auto_renew ) {
     }
 
     if ( $issue->auto_renew ) {
+
+        if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
+            return ( 0, 'auto_account_expired' );
+        }
+
         if ( defined $issuing_rule->no_auto_renewal_after
                 and $issuing_rule->no_auto_renewal_after ne "" ) {
             # Get issue_date and add no_auto_renewal_after
         if ( defined $issuing_rule->no_auto_renewal_after
                 and $issuing_rule->no_auto_renewal_after ne "" ) {
             # Get issue_date and add no_auto_renewal_after
@@ -2717,7 +2741,7 @@ sub CanBookBeRenewed {
 
         if ( C4::Context->preference('OPACFineNoRenewalsBlockAutoRenew') ) {
             my $fine_no_renewals = C4::Context->preference("OPACFineNoRenewals");
 
         if ( C4::Context->preference('OPACFineNoRenewalsBlockAutoRenew') ) {
             my $fine_no_renewals = C4::Context->preference("OPACFineNoRenewals");
-            my ( $amountoutstanding ) = C4::Members::GetMemberAccountRecords($patron->borrowernumber);
+            my $amountoutstanding = $patron->account->balance;
             if ( $amountoutstanding and $amountoutstanding > $fine_no_renewals ) {
                 return ( 0, "auto_too_much_oweing" );
             }
             if ( $amountoutstanding and $amountoutstanding > $fine_no_renewals ) {
                 return ( 0, "auto_too_much_oweing" );
             }
@@ -2790,17 +2814,15 @@ sub AddRenewal {
     my $itemnumber      = shift or return;
     my $branch          = shift;
     my $datedue         = shift;
     my $itemnumber      = shift or return;
     my $branch          = shift;
     my $datedue         = shift;
-    my $lastreneweddate = shift || DateTime->now(time_zone => C4::Context->tz)->ymd();
+    my $lastreneweddate = shift || DateTime->now(time_zone => C4::Context->tz);
 
 
-    my $item   = GetItem($itemnumber) or return;
-    my $item_object = Koha::Items->find( $itemnumber ); # Should replace $item
+    my $item_object   = Koha::Items->find($itemnumber) or return;
     my $biblio = $item_object->biblio;
     my $biblio = $item_object->biblio;
+    my $issue  = $item_object->checkout;
+    my $item_unblessed = $item_object->unblessed;
 
     my $dbh = C4::Context->dbh;
 
 
     my $dbh = C4::Context->dbh;
 
-    # Find the issues record for this book
-    my $issue = Koha::Checkouts->find( { itemnumber => $itemnumber } );
-
     return unless $issue;
 
     $borrowernumber ||= $issue->borrowernumber;
     return unless $issue;
 
     $borrowernumber ||= $issue->borrowernumber;
@@ -2813,23 +2835,35 @@ sub AddRenewal {
     my $patron = Koha::Patrons->find( $borrowernumber ) or return; # FIXME Should do more than just return
     my $patron_unblessed = $patron->unblessed;
 
     my $patron = Koha::Patrons->find( $borrowernumber ) or return; # FIXME Should do more than just return
     my $patron_unblessed = $patron->unblessed;
 
+    my $circ_library = Koha::Libraries->find( _GetCircControlBranch($item_unblessed, $patron_unblessed) );
+
     if ( C4::Context->preference('CalculateFinesOnReturn') && $issue->is_overdue ) {
     if ( C4::Context->preference('CalculateFinesOnReturn') && $issue->is_overdue ) {
-        _CalculateAndUpdateFine( { issue => $issue, item => $item, borrower => $patron_unblessed } );
+        _CalculateAndUpdateFine( { issue => $issue, item => $item_unblessed, borrower => $patron_unblessed } );
     }
     _FixOverduesOnReturn( $borrowernumber, $itemnumber );
 
     # If the due date wasn't specified, calculate it by adding the
     # book's loan length to today's date or the current due date
     # based on the value of the RenewalPeriodBase syspref.
     }
     _FixOverduesOnReturn( $borrowernumber, $itemnumber );
 
     # If the due date wasn't specified, calculate it by adding the
     # book's loan length to today's date or the current due date
     # based on the value of the RenewalPeriodBase syspref.
+    my $itemtype = $item_object->effective_itemtype;
     unless ($datedue) {
 
     unless ($datedue) {
 
-        my $itemtype = $item_object->effective_itemtype;
         $datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
                                         dt_from_string( $issue->date_due, 'sql' ) :
                                         DateTime->now( time_zone => C4::Context->tz());
         $datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
                                         dt_from_string( $issue->date_due, 'sql' ) :
                                         DateTime->now( time_zone => C4::Context->tz());
-        $datedue =  CalcDateDue($datedue, $itemtype, _GetCircControlBranch($item, $patron_unblessed), $patron_unblessed, 'is a renewal');
+        $datedue =  CalcDateDue($datedue, $itemtype, $circ_library, $patron_unblessed, 'is a renewal');
     }
 
     }
 
+    my $fees = Koha::Charges::Fees->new(
+        {
+            patron    => $patron,
+            library   => $circ_library,
+            item      => $item_object,
+            from_date => dt_from_string( $issue->date_due, 'sql' ),
+            to_date   => dt_from_string($datedue),
+        }
+    );
+
     # Update the issues record to have the new due date, and a new count
     # of how many times it has been renewed.
     my $renews = $issue->renewals + 1;
     # Update the issues record to have the new due date, and a new count
     # of how many times it has been renewed.
     my $renews = $issue->renewals + 1;
@@ -2841,24 +2875,25 @@ sub AddRenewal {
     $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
     $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 = $item->{renewals} + 1;
-    ModItem({ renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $item->{biblionumber}, $itemnumber);
+    $renews = $item_object->renewals + 1;
+    ModItem( { renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $item_object->biblionumber, $itemnumber, { log_action => 0 } );
 
 
-    # Charge a new rental fee, if applicable?
+    # Charge a new rental fee, if applicable
     my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
     if ( $charge > 0 ) {
     my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
     if ( $charge > 0 ) {
-        my $accountno = getnextacctno( $borrowernumber );
-        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(),?,?,?,?,?,?,?,?)"
-        );
-        $sth->execute( $borrowernumber, $accountno, $charge, $manager_id,
-            "Renewal of Rental Item " . $biblio->title . " $item->{'barcode'}",
-            'Rent', $charge, $itemnumber );
+        my $description = "Renewal of Rental Item " . $biblio->title . " " .$item_object->barcode;
+        AddIssuingCharge($issue, $charge, $description);
+    }
+
+    # Charge a new accumulate rental fee, if applicable
+    my $itemtype_object = Koha::ItemTypes->find( $itemtype );
+    if ( $itemtype_object ) {
+        my $accumulate_charge = $fees->accumulate_rentalcharge();
+        if ( $accumulate_charge > 0 ) {
+            my $type_desc = "Renewal of Daily Rental Item " . $biblio->title . " $item_unblessed->{'barcode'}";
+            AddIssuingCharge( $issue, $accumulate_charge, $type_desc )
+        }
+        $charge += $accumulate_charge;
     }
 
     # Send a renewal slip according to checkout alert preferencei
     }
 
     # Send a renewal slip according to checkout alert preferencei
@@ -2867,14 +2902,14 @@ sub AddRenewal {
         my %conditions        = (
             branchcode   => $branch,
             categorycode => $patron->categorycode,
         my %conditions        = (
             branchcode   => $branch,
             categorycode => $patron->categorycode,
-            item_type    => $item->{itype},
+            item_type    => $itemtype,
             notification => 'CHECKOUT',
         );
         if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
             SendCirculationAlert(
                 {
                     type     => 'RENEWAL',
             notification => 'CHECKOUT',
         );
         if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
             SendCirculationAlert(
                 {
                     type     => 'RENEWAL',
-                    item     => $item,
+                    item     => $item_unblessed,
                     borrower => $patron->unblessed,
                     branch   => $branch,
                 }
                     borrower => $patron->unblessed,
                     branch   => $branch,
                 }
@@ -2902,9 +2937,10 @@ sub AddRenewal {
             type           => 'renew',
             amount         => $charge,
             itemnumber     => $itemnumber,
             type           => 'renew',
             amount         => $charge,
             itemnumber     => $itemnumber,
-            itemtype       => $item->{itype},
+            itemtype       => $itemtype,
+            location       => $item_object->location,
             borrowernumber => $borrowernumber,
             borrowernumber => $borrowernumber,
-            ccode          => $item->{'ccode'}
+            ccode          => $item_object->ccode,
         }
     );
 
         }
     );
 
@@ -2922,7 +2958,7 @@ sub GetRenewCount {
     my $renewsleft    = 0;
 
     my $patron = Koha::Patrons->find( $bornum );
     my $renewsleft    = 0;
 
     my $patron = Koha::Patrons->find( $bornum );
-    my $item     = GetItem($itemno);
+    my $item   = Koha::Items->find($itemno);
 
     return (0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
 
 
     return (0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
 
@@ -2939,11 +2975,11 @@ sub GetRenewCount {
     my $data = $sth->fetchrow_hashref;
     $renewcount = $data->{'renewals'} if $data->{'renewals'};
     # $item and $borrower should be calculated
     my $data = $sth->fetchrow_hashref;
     $renewcount = $data->{'renewals'} if $data->{'renewals'};
     # $item and $borrower should be calculated
-    my $branchcode = _GetCircControlBranch($item, $patron->unblessed);
+    my $branchcode = _GetCircControlBranch($item->unblessed, $patron->unblessed);
 
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
 
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
-            itemtype     => $item->{itype},
+            itemtype     => $item->effective_itemtype,
             branchcode   => $branchcode
         }
     );
             branchcode   => $branchcode
         }
     );
@@ -2978,17 +3014,17 @@ sub GetSoonestRenewDate {
 
     my $dbh = C4::Context->dbh;
 
 
     my $dbh = C4::Context->dbh;
 
-    my $item      = GetItem($itemnumber)      or return;
-    my $itemissue = Koha::Checkouts->find( { itemnumber => $itemnumber } ) or return;
+    my $item      = Koha::Items->find($itemnumber)      or return;
+    my $itemissue = $item->checkout or return;
 
     $borrowernumber ||= $itemissue->borrowernumber;
     my $patron = Koha::Patrons->find( $borrowernumber )
       or return;
 
 
     $borrowernumber ||= $itemissue->borrowernumber;
     my $patron = Koha::Patrons->find( $borrowernumber )
       or return;
 
-    my $branchcode = _GetCircControlBranch( $item, $patron->unblessed );
+    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
-            itemtype     => $item->{itype},
+            itemtype     => $item->effective_itemtype,
             branchcode   => $branchcode
         }
     );
             branchcode   => $branchcode
         }
     );
@@ -3037,17 +3073,17 @@ sub GetLatestAutoRenewDate {
 
     my $dbh = C4::Context->dbh;
 
 
     my $dbh = C4::Context->dbh;
 
-    my $item      = GetItem($itemnumber)      or return;
-    my $itemissue = Koha::Checkouts->find( { itemnumber => $itemnumber } ) or return;
+    my $item      = Koha::Items->find($itemnumber)  or return;
+    my $itemissue = $item->checkout                 or return;
 
     $borrowernumber ||= $itemissue->borrowernumber;
     my $patron = Koha::Patrons->find( $borrowernumber )
       or return;
 
 
     $borrowernumber ||= $itemissue->borrowernumber;
     my $patron = Koha::Patrons->find( $borrowernumber )
       or return;
 
-    my $branchcode = _GetCircControlBranch( $item, $patron->unblessed );
+    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
         {   categorycode => $patron->categorycode,
-            itemtype     => $item->{itype},
+            itemtype     => $item->effective_itemtype,
             branchcode   => $branchcode
         }
     );
             branchcode   => $branchcode
         }
     );
@@ -3177,39 +3213,28 @@ sub _get_discount_from_rule {
 
 =head2 AddIssuingCharge
 
 
 =head2 AddIssuingCharge
 
-  &AddIssuingCharge( $itemno, $borrowernumber, $charge )
+  &AddIssuingCharge( $checkout, $charge, [$description] )
 
 =cut
 
 sub AddIssuingCharge {
 
 =cut
 
 sub AddIssuingCharge {
-    my ( $itemnumber, $borrowernumber, $charge ) = @_;
+    my ( $checkout, $charge, $description ) = @_;
 
 
-    my $nextaccntno = getnextacctno($borrowernumber);
+    # FIXME What if checkout does not exist?
 
 
-    my $manager_id  = 0;
-    $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
-
-    my $accountline = Koha::Account::Line->new(
-        {
-            borrowernumber    => $borrowernumber,
-            itemnumber        => $itemnumber,
-            accountno         => $nextaccntno,
-            amount            => $charge,
-            amountoutstanding => $charge,
-            manager_id        => $manager_id,
-            description       => 'Rental',
-            accounttype       => 'Rent',
-            date              => \'NOW()',
-        }
-    )->store();
-
-    Koha::Account::Offset->new(
+    my $account = Koha::Account->new({ patron_id => $checkout->borrowernumber });
+    my $accountline = $account->add_debit(
         {
         {
-            debit_id => $accountline->id,
-            type     => 'Rental Fee',
-            amount   => $charge,
+            amount      => $charge,
+            description => $description,
+            note        => undef,
+            user_id     => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
+            library_id  => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
+            type        => 'rent',
+            item_id     => $checkout->itemnumber,
+            issue_id    => $checkout->issue_id,
         }
         }
-    )->store();
+    );
 }
 
 =head2 GetTransfers
 }
 
 =head2 GetTransfers
@@ -3548,6 +3573,9 @@ return $exist;
 
 Code is either an itemtype or collection doe depending on the pref BranchTransferLimitsType
 
 
 Code is either an itemtype or collection doe depending on the pref BranchTransferLimitsType
 
+Deprecated in favor of Koha::Item::Transfer::Limits->find/search and
+Koha::Item->can_be_transferred.
+
 =cut
 
 sub IsBranchTransferAllowed {
 =cut
 
 sub IsBranchTransferAllowed {
@@ -3576,6 +3604,8 @@ sub IsBranchTransferAllowed {
 
 $code is either itemtype or collection code depending on what the pref BranchTransferLimitsType is set to.
 
 
 $code is either itemtype or collection code depending on what the pref BranchTransferLimitsType is set to.
 
+Deprecated in favor of Koha::Item::Transfer::Limit->new.
+
 =cut
 
 sub CreateBranchTransferLimit {
 =cut
 
 sub CreateBranchTransferLimit {
@@ -3597,6 +3627,10 @@ Deletes all the library transfer limits for one library.  Returns the
 number of limits deleted, 0e0 if no limits were deleted, or undef if
 no arguments are supplied.
 
 number of limits deleted, 0e0 if no limits were deleted, or undef if
 no arguments are supplied.
 
+Deprecated in favor of Koha::Item::Transfer::Limits->search({
+    fromBranch => $fromBranch
+    })->delete.
+
 =cut
 
 sub DeleteBranchTransferLimits {
 =cut
 
 sub DeleteBranchTransferLimits {
@@ -3612,8 +3646,8 @@ sub ReturnLostItem{
 
     MarkIssueReturned( $borrowernumber, $itemnum );
     my $patron = Koha::Patrons->find( $borrowernumber );
 
     MarkIssueReturned( $borrowernumber, $itemnum );
     my $patron = Koha::Patrons->find( $borrowernumber );
-    my $item = C4::Items::GetItem( $itemnum );
-    my $old_note = ($item->{'paidfor'} && ($item->{'paidfor'} ne q{})) ? $item->{'paidfor'}.' / ' : q{};
+    my $item = Koha::Items->find($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 = $patron->firstname . ' ' . $patron->surname . ' ' . $patron->cardnumber;
     my @datearr = localtime(time);
     my $date = ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3];
     my $bor = $patron->firstname . ' ' . $patron->surname . ' ' . $patron->cardnumber;
@@ -3622,9 +3656,20 @@ sub ReturnLostItem{
 
 
 sub LostItem{
 
 
 sub LostItem{
-    my ($itemnumber, $mark_returned) = @_;
+    my ($itemnumber, $mark_lost_from, $force_mark_returned) = @_;
 
 
-    $mark_returned //= C4::Context->preference('MarkLostItemsAsReturned');
+    unless ( $mark_lost_from ) {
+        # Temporary check to avoid regressions
+        die q|LostItem called without $mark_lost_from, check the API.|;
+    }
+
+    my $mark_returned;
+    if ( $force_mark_returned ) {
+        $mark_returned = 1;
+    } else {
+        my $pref = C4::Context->preference('MarkLostItemsAsReturned') // q{};
+        $mark_returned = ( $pref =~ m|$mark_lost_from| );
+    }
 
     my $dbh = C4::Context->dbh();
     my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title 
 
     my $dbh = C4::Context->dbh();
     my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title 
@@ -3639,18 +3684,23 @@ sub LostItem{
     if ( my $borrowernumber = $issues->{borrowernumber} ){
         my $patron = Koha::Patrons->find( $borrowernumber );
 
     if ( my $borrowernumber = $issues->{borrowernumber} ){
         my $patron = Koha::Patrons->find( $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
-        }
+        my $fix = _FixOverduesOnReturn($borrowernumber, $itemnumber, C4::Context->preference('WhenLostForgiveFine'), 0); # 1, 0 = exemptfine, no-dropbox
+        defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!";  # zero is OK, check defined
+
         if (C4::Context->preference('WhenLostChargeReplacementFee')){
         if (C4::Context->preference('WhenLostChargeReplacementFee')){
-            C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'}");
+            C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'} $issues->{'itemcallnumber'}");
             #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,$patron->privacy) if $mark_returned;
+        MarkIssueReturned($borrowernumber,$itemnumber,undef,$patron->privacy) if $mark_returned;
     }
     }
+
+    #When item is marked lost automatically cancel its outstanding transfers and set items holdingbranch to the transfer source branch (frombranch)
+    if (my ( $datesent,$frombranch,$tobranch ) = GetTransfers($itemnumber)) {
+        ModItem({holdingbranch => $frombranch}, undef, $itemnumber);
+    }
+    my $transferdeleted = DeleteTransfer($itemnumber);
 }
 
 sub GetOfflineOperations {
 }
 
 sub GetOfflineOperations {
@@ -3714,13 +3764,13 @@ sub ProcessOfflineReturn {
             MarkIssueReturned(
                 $issue->{borrowernumber},
                 $itemnumber,
             MarkIssueReturned(
                 $issue->{borrowernumber},
                 $itemnumber,
-                undef,
                 $operation->{timestamp},
             );
             ModItem(
                 { renewals => 0, onloan => undef },
                 $issue->{'biblionumber'},
                 $operation->{timestamp},
             );
             ModItem(
                 { renewals => 0, onloan => undef },
                 $issue->{'biblionumber'},
-                $itemnumber
+                $itemnumber,
+                { log_action => 0 }
             );
             return "Success.";
         } else {
             );
             return "Success.";
         } else {
@@ -3748,7 +3798,6 @@ sub ProcessOfflineIssue {
             MarkIssueReturned(
                 $issue->{borrowernumber},
                 $itemnumber,
             MarkIssueReturned(
                 $issue->{borrowernumber},
                 $itemnumber,
-                undef,
                 $operation->{timestamp},
             );
         }
                 $operation->{timestamp},
             );
         }
@@ -3769,15 +3818,13 @@ sub ProcessOfflineIssue {
 sub ProcessOfflinePayment {
     my $operation = shift;
 
 sub ProcessOfflinePayment {
     my $operation = shift;
 
-    my $patron = Koha::Patrons->find( { cardnumber => $operation->{cardnumber} });
-    my $amount = $operation->{amount};
+    my $patron = Koha::Patrons->find({ cardnumber => $operation->{cardnumber} });
 
 
-    Koha::Account->new( { patron_id => $patron->id } )->pay( { amount => $amount } );
+    $patron->account->pay({ amount => $operation->{amount}, library_id => $operation->{branchcode} });
 
 
-    return "Success."
+    return "Success.";
 }
 
 }
 
-
 =head2 TransferSlip
 
   TransferSlip($user_branch, $itemnumber, $barcode, $to_branch)
 =head2 TransferSlip
 
   TransferSlip($user_branch, $itemnumber, $barcode, $to_branch)
@@ -3789,8 +3836,12 @@ sub ProcessOfflinePayment {
 sub TransferSlip {
     my ($branch, $itemnumber, $barcode, $to_branch) = @_;
 
 sub TransferSlip {
     my ($branch, $itemnumber, $barcode, $to_branch) = @_;
 
-    my $item =  GetItem( $itemnumber, $barcode )
-      or return;
+    my $item =
+      $itemnumber
+      ? Koha::Items->find($itemnumber)
+      : Koha::Items->find( { barcode => $barcode } );
+
+    $item or return;
 
     return C4::Letters::GetPreparedLetter (
         module => 'circulation',
 
     return C4::Letters::GetPreparedLetter (
         module => 'circulation',
@@ -3798,8 +3849,8 @@ sub TransferSlip {
         branchcode => $branch,
         tables => {
             'branches'    => $to_branch,
         branchcode => $branch,
         tables => {
             'branches'    => $to_branch,
-            'biblio'      => $item->{biblionumber},
-            'items'       => $item,
+            'biblio'      => $item->biblionumber,
+            'items'       => $item->unblessed,
         },
     );
 }
         },
     );
 }
@@ -3959,6 +4010,7 @@ sub GetTopIssues {
 
     my $dbh = C4::Context->dbh;
     my $query = q{
 
     my $dbh = C4::Context->dbh;
     my $query = q{
+        SELECT * FROM (
         SELECT b.biblionumber, b.title, b.author, bi.itemtype, bi.publishercode,
           bi.place, bi.publicationyear, b.copyrightdate, bi.pages, bi.size,
           i.ccode, SUM(i.issues) AS count
         SELECT b.biblionumber, b.title, b.author, bi.itemtype, bi.publishercode,
           bi.place, bi.publicationyear, b.copyrightdate, bi.pages, bi.size,
           i.ccode, SUM(i.issues) AS count
@@ -3996,11 +4048,13 @@ sub GetTopIssues {
     }
 
     $query .= q{
     }
 
     $query .= q{
-        GROUP BY b.biblionumber
-        HAVING count > 0
+        GROUP BY b.biblionumber, b.title, b.author, bi.itemtype, bi.publishercode,
+          bi.place, bi.publicationyear, b.copyrightdate, bi.pages, bi.size,
+          i.ccode
         ORDER BY count DESC
     };
 
         ORDER BY count DESC
     };
 
+    $query .= q{ ) xxx WHERE count > 0 };
     $count = int($count);
     if ($count > 0) {
         $query .= "LIMIT $count";
     $count = int($count);
     if ($count > 0) {
         $query .= "LIMIT $count";
@@ -4033,13 +4087,11 @@ sub _CalculateAndUpdateFine {
       : ( $control eq 'PatronLibrary' )   ? $borrower->{branchcode}
       :                                     $issue->branchcode;
 
       : ( $control eq 'PatronLibrary' )   ? $borrower->{branchcode}
       :                                     $issue->branchcode;
 
-    my $date_returned = $return_date ? dt_from_string($return_date) : dt_from_string();
+    my $date_returned = $return_date ? $return_date : dt_from_string();
 
 
-    my ( $amount, $type, $unitcounttotal ) =
+    my ( $amount, $unitcounttotal, $unitcount  ) =
       C4::Overdues::CalcFine( $item, $borrower->{categorycode}, $control_branchcode, $datedue, $date_returned );
 
       C4::Overdues::CalcFine( $item, $borrower->{categorycode}, $control_branchcode, $datedue, $date_returned );
 
-    $type ||= q{};
-
     if ( C4::Context->preference('finesMode') eq 'production' ) {
         if ( $amount > 0 ) {
             C4::Overdues::UpdateFine({
     if ( C4::Context->preference('finesMode') eq 'production' ) {
         if ( $amount > 0 ) {
             C4::Overdues::UpdateFine({
@@ -4047,7 +4099,6 @@ sub _CalculateAndUpdateFine {
                 itemnumber     => $issue->itemnumber,
                 borrowernumber => $issue->borrowernumber,
                 amount         => $amount,
                 itemnumber     => $issue->itemnumber,
                 borrowernumber => $issue->borrowernumber,
                 amount         => $amount,
-                type           => $type,
                 due            => output_pref($datedue),
             });
         }
                 due            => output_pref($datedue),
             });
         }
@@ -4061,13 +4112,36 @@ sub _CalculateAndUpdateFine {
                 itemnumber     => $issue->itemnumber,
                 borrowernumber => $issue->borrowernumber,
                 amount         => 0,
                 itemnumber     => $issue->itemnumber,
                 borrowernumber => $issue->borrowernumber,
                 amount         => 0,
-                type           => $type,
                 due            => output_pref($datedue),
             });
         }
     }
 }
 
                 due            => output_pref($datedue),
             });
         }
     }
 }
 
+sub _item_denied_renewal {
+    my ($params) = @_;
+
+    my $item = $params->{item};
+    return unless $item;
+
+    my $denyingrules = Koha::Config::SysPrefs->find('ItemsDeniedRenewal')->get_yaml_pref_hash();
+    return unless $denyingrules;
+    foreach my $field (keys %$denyingrules) {
+        my $val = $item->$field;
+        if( !defined $val) {
+            if ( any { !defined $_ }  @{$denyingrules->{$field}} ){
+                return 1;
+            }
+        } elsif (any { defined($_) && $val eq $_ } @{$denyingrules->{$field}}) {
+           # If the results matches the values in the syspref
+           # We return true if match found
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
 1;
 
 __END__
 1;
 
 __END__