Bug 14577 - Allow restriction of checkouts based on fines of guarantor's guarantees
authorKyle M Hall <kyle@bywatersolutions.com>
Thu, 11 Feb 2016 01:23:09 +0000 (01:23 +0000)
committerKyle M Hall <kyle@bywatersolutions.com>
Fri, 29 Apr 2016 11:54:23 +0000 (11:54 +0000)
This enhancment allows a library to prevent patrons from checking out
items if his or her guarantees own too much.

Test Plan:
1) Apply this patch
2) Find or create a patron with a guarantor
3) Add a fine to the patron's account
4) Set the new system preference NoIssuesChargeGuarantees to be less
   than the amount owed by the patron
4) Attempt to check out an item to the guarantor, you will either
   be warned or prevented from checking out based on your system
   settings.

Signed-off-by: Cathi Wiggin <CWIGGINS@arcadiaca.gov>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
C4/Circulation.pm
C4/Members.pm
Koha/Patron.pm
circ/circulation.pl
installer/data/mysql/atomicupdate/bug_14577.sql [new file with mode: 0644]
installer/data/mysql/sysprefs.sql
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref
koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
t/db_dependent/Circulation/NoIssuesChargeGuarantees.t [new file with mode: 0644]
t/db_dependent/Patron.t

index 650dc12..811cc98 100644 (file)
@@ -55,6 +55,7 @@ use Koha::Libraries;
 use Koha::Holds;
 use Carp;
 use List::MoreUtils qw( uniq );
+use Scalar::Util qw( looks_like_number );
 use Date::Calc qw(
   Today
   Today_and_Now
@@ -844,9 +845,32 @@ sub CanBookBeIssued {
     # DEBTS
     my ($balance, $non_issue_charges, $other_charges) =
       C4::Members::GetMemberAccountBalance( $borrower->{'borrowernumber'} );
+
     my $amountlimit = C4::Context->preference("noissuescharge");
     my $allowfineoverride = C4::Context->preference("AllowFineOverride");
     my $allfinesneedoverride = C4::Context->preference("AllFinesNeedOverride");
+
+    # Check the debt of this patrons 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_non_issues_charges;
+        foreach my $g ( @guarantees ) {
+            my ( $b, $n, $o ) = C4::Members::GetMemberAccountBalance( $g->id );
+            $guarantees_non_issues_charges += $n;
+        }
+
+        if ( $guarantees_non_issues_charges > $no_issues_charge_guarantees && !$inprocess && !$allowfineoverride) {
+            $issuingimpossible{DEBT_GUARANTEES} = sprintf( "%.2f", $guarantees_non_issues_charges );
+        } elsif ( $guarantees_non_issues_charges > $no_issues_charge_guarantees && !$inprocess && $allowfineoverride) {
+            $needsconfirmation{DEBT_GUARANTEES} = sprintf( "%.2f", $guarantees_non_issues_charges );
+        } elsif ( $allfinesneedoverride && $guarantees_non_issues_charges > 0 && $guarantees_non_issues_charges <= $no_issues_charge_guarantees && !$inprocess ) {
+            $needsconfirmation{DEBT_GUARANTEES} = sprintf( "%.2f", $guarantees_non_issues_charges );
+        }
+    }
+
     if ( C4::Context->preference("IssuingInProcess") ) {
         if ( $non_issue_charges > $amountlimit && !$inprocess && !$allowfineoverride) {
             $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges );
@@ -865,6 +889,7 @@ sub CanBookBeIssued {
             $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
         }
     }
+
     if ($balance > 0 && $other_charges > 0) {
         $alerts{OTHER_CHARGES} = sprintf( "%.2f", $other_charges );
     }
index ed82f86..a3e1377 100644 (file)
@@ -24,6 +24,7 @@ use strict;
 #use warnings; FIXME - Bug 2505
 use C4::Context;
 use String::Random qw( random_string );
+use Scalar::Util qw( looks_like_number );
 use Date::Calc qw/Today Add_Delta_YM check_date Date_to_Days/;
 use C4::Log; # logaction
 use C4::Overdues;
@@ -326,6 +327,28 @@ sub patronflags {
         $flaginfo{'amount'}  = sprintf "%.02f", $balance;
         $flags{'CREDITS'} = \%flaginfo;
     }
+
+    # Check the debt of the guarntees of this patron
+    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( $patroninformation->{borrowernumber} );
+        my @guarantees = $p->guarantees();
+        my $guarantees_non_issues_charges;
+        foreach my $g ( @guarantees ) {
+            my ( $b, $n, $o ) = C4::Members::GetMemberAccountBalance( $g->id );
+            $guarantees_non_issues_charges += $n;
+        }
+
+        if ( $guarantees_non_issues_charges > $no_issues_charge_guarantees ) {
+            my %flaginfo;
+            $flaginfo{'message'} = sprintf 'patron guarantees owe %.02f', $guarantees_non_issues_charges;
+            $flaginfo{'amount'}  = sprintf "%.02f", $guarantees_non_issues_charges;
+            $flaginfo{'noissues'} = 1 unless C4::Context->preference("allowfineoverride");
+            $flags{'CHARGES_GUARANTEES'} = \%flaginfo;
+        }
+    }
+
     if (   $patroninformation->{'gonenoaddress'}
         && $patroninformation->{'gonenoaddress'} == 1 )
     {
index 68cb822..ac62594 100644 (file)
@@ -22,6 +22,7 @@ use Modern::Perl;
 use Carp;
 
 use Koha::Database;
+use Koha::Patrons;
 use Koha::Patron::Images;
 
 use base qw(Koha::Object);
@@ -65,7 +66,7 @@ Returns the guarantees (list of Koha::Patron) of this patron
 sub guarantees {
     my ( $self ) = @_;
 
-    return Koha::Patrons->search({ guarantorid => $self->borrowernumber });
+    return Koha::Patrons->search( { guarantorid => $self->borrowernumber } );
 }
 
 =head3 siblings
index d128321..981bef7 100755 (executable)
@@ -499,6 +499,14 @@ foreach my $flag ( sort keys %$flags ) {
                 charges_is_blocker => 1
             );
         }
+        elsif ( $flag eq 'CHARGES_GUARANTEES' ) {
+            $template->param(
+                charges_guarantees    => 'true',
+                chargesmsg_guarantees => $flags->{'CHARGES_GUARANTEES'}->{'message'},
+                chargesamount_guarantees => $flags->{'CHARGES_GUARANTEES'}->{'amount'},
+                charges_guarantees_is_blocker => 1
+            );
+        }
         elsif ( $flag eq 'CREDITS' ) {
             $template->param(
                 credits    => 'true',
@@ -515,6 +523,13 @@ foreach my $flag ( sort keys %$flags ) {
                 chargesamount => $flags->{'CHARGES'}->{'amount'},
             );
         }
+        elsif ( $flag eq 'CHARGES_GUARANTEES' ) {
+            $template->param(
+                charges_guarantees    => 'true',
+                chargesmsg_guarantees => $flags->{'CHARGES_GUARANTEES'}->{'message'},
+                chargesamount_guarantees => $flags->{'CHARGES_GUARANTEES'}->{'amount'},
+            );
+        }
         elsif ( $flag eq 'CREDITS' ) {
             $template->param(
                 credits    => 'true',
diff --git a/installer/data/mysql/atomicupdate/bug_14577.sql b/installer/data/mysql/atomicupdate/bug_14577.sql
new file mode 100644 (file)
index 0000000..ab62900
--- /dev/null
@@ -0,0 +1,2 @@
+INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
+('NoIssuesChargeGuarantees','','','Define maximum amount withstanding before check outs are blocked','Integer');
index fed0ed9..22d04f0 100644 (file)
@@ -243,6 +243,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
 ('NewItemsDefaultLocation','','','If set, all new items will have a location of the given Location Code ( Authorized Value type LOC )',''),
 ('NewsAuthorDisplay','none','none|opac|staff|both','Display the author name for news items.','Choice'),
 ('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'),
+('NoIssuesChargeGuarantees','','','Define maximum amount withstanding before check outs are blocked','Integer'),
 ('noItemTypeImages','0',NULL,'If ON, disables item-type images','YesNo'),
 ('NoLoginInstructions', '', '60|10', 'Instructions to display on the OPAC login form when a patron is not logged in', 'Textarea'),
 ('NorwegianPatronDBEnable','0',NULL,'Enable communication with the Norwegian national patron database.', 'YesNo'),
index 37b8d57..9a37608 100644 (file)
@@ -304,6 +304,11 @@ Circulation:
               class: integer
             - '[% local_currency %] in fines.'
         -
+            - Prevent a patron from checking out if the patron has guarantees owing in total more than
+            - pref: NoIssuesChargeGuarantees
+              class: integer
+            - '[% local_currency %] in fines.'
+        -
             - pref: RentalsInNoissuesCharge
               choices:
                   yes: Include
index 616a2b2..bfedf5c 100644 (file)
@@ -234,6 +234,11 @@ $(document).ready(function() {
 [% IF ( DEBT ) %]
     <li>The patron has a debt of [% DEBT %].</li>
 [% END %]
+
+[% IF ( DEBT_GUARANTEES ) %]
+    <li>The patron's guarantees collectively have a debt of [% DEBT_GUARANTEES %].</li>
+[% END %]
+
 [% IF ( RENTALCHARGE && RENTALCHARGE > 0 ) %]
     <li>Rental charge for this item: [% RENTALCHARGE %]</li>
 [% END %]
@@ -791,21 +796,32 @@ No patron matched <span class="ex">[% message %]</span>
                 [% IF ( odues ) %]<li>[% IF ( nonreturns ) %]<span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE</span>. See highlighted items <a href="#checkouts">below</a>[% END %]</li>
             [% END %]
 
-               [% IF ( charges ) %]
-                           <li>
-            <span class="circ-hlt">Fees &amp; Charges:</span> Patron has  <a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Outstanding fees &amp; charges[% IF ( chargesamount ) %] of [% chargesamount %][% END %]</a>.
-                [% IF ( charges_is_blocker ) %]
-                    <span class="circ-hlt">Checkouts are BLOCKED because fine balance is OVER THE LIMIT.</span>
-                [% END %]
-            <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]">Make payment</a> or
-            <a href="/cgi-bin/koha/members/paycollect.pl?borrowernumber=[% borrowernumber %]">Pay all fines</a></li>
-                       [% END %]
+            [% IF ( charges ) %]
+                <li>
+                    <span class="circ-hlt">Fees &amp; Charges:</span> Patron has  <a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Outstanding fees &amp; charges[% IF ( chargesamount ) %] of [% chargesamount %][% END %]</a>.
+                        [% IF ( charges_is_blocker ) %]
+                            <span class="circ-hlt">Checkouts are BLOCKED because fine balance is OVER THE LIMIT.</span>
+                        [% END %]
+                    <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]">Make payment</a> or
+                    <a href="/cgi-bin/koha/members/paycollect.pl?borrowernumber=[% borrowernumber %]">Pay all fines</a>
+                </li>
+            [% END %]
 
-               [% IF ( credits ) %]
-                       <li>
-                <span class="circ-hlt">Credits:</span> Patron has a credit[% IF ( creditsamount ) %] of [% creditsamount %][% END %]
-            </li>
-                       [% END %]
+            [% IF ( charges_guarantees ) %]
+                <li>
+                    <span class="circ-hlt">Fees &amp; Charges:</span> Patron's guarantees collectively owe [% chargesamount_guarantees %].
+                        [% IF ( charges_guarantees_is_blocker ) %]
+                            <span class="circ-hlt">Checkouts are BLOCKED because fine balance is OVER THE LIMIT.</span>
+                        [% END %]
+                </li>
+            [% END %]
+
+
+            [% IF ( credits ) %]
+                <li>
+                    <span class="circ-hlt">Credits:</span> Patron has a credit[% IF ( creditsamount ) %] of [% creditsamount %][% END %]
+                </li>
+            [% END %]
 
                        </ul>
         </div>
diff --git a/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t b/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t
new file mode 100644 (file)
index 0000000..614c513
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Test::More tests => 2;
+
+use t::lib::TestBuilder;
+
+use C4::Accounts qw( manualinvoice );
+use C4::Circulation qw( CanBookBeIssued );
+
+my $schema = Koha::Database->new->schema;
+$schema->storage->txn_begin;
+
+my $builder = t::lib::TestBuilder->new();
+
+my $item = $builder->build(
+    {
+        source => 'Item',
+        value  => {
+            notforloan => 0,
+            withdrawn  => 0
+        }
+    }
+);
+
+my $patron = $builder->build(
+    {
+        source => 'Borrower',
+    }
+);
+my $guarantee = $builder->build(
+    {
+        source => 'Borrower',
+        value  => {
+            guarantorid => $patron->{borrowernumber},
+        }
+    }
+);
+
+C4::Context->set_preference( 'NoIssuesChargeGuarantees', '5.00' );
+
+my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $item->{barcode} );
+is( $issuingimpossible->{DEBT_GUARANTEES}, undef, "Patron can check out item" );
+
+manualinvoice( $guarantee->{borrowernumber}, undef, undef, 'L', 10.00 );
+( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $item->{barcode} );
+is( $issuingimpossible->{DEBT_GUARANTEES}, '10.00', "Patron cannot check out item due to debt for guarantee" );
+
+$schema->storage->txn_rollback;
+
+1;
index 11c57fe..0140013 100755 (executable)
@@ -17,7 +17,7 @@
 
 use Modern::Perl;
 
-use Test::More tests => 13;
+use Test::More tests => 15;
 use Test::Warn;
 
 use C4::Context;
@@ -44,6 +44,23 @@ $object->surname("Test Surname");
 $object->store();
 
 is( $object->in_storage, 1, "Object is now stored" );
+my $guarantee1 = Koha::Patron->new(
+    {
+        categorycode => $categorycode,
+        branchcode   => $branchcode,
+        guarantorid  => $object->id
+    }
+)->store();
+my $guarantee2 = Koha::Patron->new(
+    {
+        categorycode => $categorycode,
+        branchcode   => $branchcode,
+        guarantorid  => $object->id
+    }
+)->store();
+my @guarantees = $object->guarantees();
+is( $guarantees[0]->id, $guarantee1->id, "First guarantee matchs" );
+is( $guarantees[1]->id, $guarantee2->id, "Second guarantee matchs" );
 
 my $borrowernumber = $object->borrowernumber;