[Koha-patches] [PATCH] bug_7420: Added overduefinescap to issuingrules

Srdjan srdjan at catalyst.net.nz
Thu May 31 02:04:26 CEST 2012


Replaced existing MaxFine syspref logic with overduefinescap.
Repurposed MaxFine to be the overall overdue limit for all items
overdue. Implemented new MaxFine logic in UpdateFine().
---
 C4/Circulation.pm                                  |    2 +-
 C4/Overdues.pm                                     |   48 +++++++++++++++-----
 admin/smart-rules.pl                               |    9 ++--
 installer/data/mysql/kohastructure.sql             |    1 +
 installer/data/mysql/sysprefs.sql                  |    2 +-
 installer/data/mysql/updatedatabase.pl             |   15 ++++++
 .../prog/en/modules/admin/preferences/patrons.pref |    3 +-
 .../prog/en/modules/admin/smart-rules.tt           |    3 ++
 misc/cronjobs/fines.pl                             |    4 +-
 misc/cronjobs/staticfines.pl                       |    2 +-
 10 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index c26de76..91e35d8 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -1615,7 +1615,7 @@ sub AddReturn {
 
         if ($borrowernumber) {
         if($issue->{'overdue'}){
-                my ( $amount, $type, $daycounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today );
+                my ( $amount, $type, $unitcounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today );
                 $type ||= q{};
         if ( $amount > 0 && ( C4::Context->preference('finesMode') eq 'production' )) {
           C4::Overdues::UpdateFine(
diff --git a/C4/Overdues.pm b/C4/Overdues.pm
index c7430c9..bcc641d 100644
--- a/C4/Overdues.pm
+++ b/C4/Overdues.pm
@@ -241,8 +241,8 @@ C<$amount> is the fine owed by the patron (see above).
 C<$chargename> is the chargename field from the applicable record in
 the categoryitem table, whatever that is.
 
-C<$daycount> is the number of days between start and end dates, Calendar adjusted (where needed), 
-minus any applicable grace period.
+C<$unitcount> is the number of chargeable units (days between start and end dates, Calendar adjusted where needed, 
+minus any applicable grace period, or hours)
 
 FIXME - What is chargename supposed to be ?
 
@@ -268,10 +268,9 @@ sub CalcFine {
     } else {
         # a zero (or null)  chargeperiod means no charge.
     }
-    if(C4::Context->preference('maxFine') && ( $amount > C4::Context->preference('maxFine'))) {
-        $amount = C4::Context->preference('maxFine');
-    }
-    return ($amount, $data->{chargename}, $units_minus_grace);
+    $amount = $data->{overduefinescap} if $data->{overduefinescap} && $amount > $data->{overduefinescap};
+    $debug and warn sprintf("CalcFine returning (%s, %s, %s, %s)", $amount, $data->{'chargename'}, $units_minus_grace, $chargeable_units);
+    return ($amount, $data->{'chargename'}, $units_minus_grace, $chargeable_units);
     # FIXME: chargename is NEVER populated anywhere.
 }
 
@@ -521,14 +520,39 @@ sub UpdateFine {
 	#   "REF" is Cash Refund
     my $sth = $dbh->prepare(
         "SELECT * FROM accountlines
-		WHERE itemnumber=?
-		AND   borrowernumber=?
-		AND   accounttype IN ('FU','O','F','M')
-		AND   description like ? "
+		WHERE borrowernumber=?
+		AND   accounttype IN ('FU','O','F','M')"
     );
-    $sth->execute( $itemnum, $borrowernumber, "%$due%" );
+    $sth->execute( $borrowernumber );
+    my $data;
+    my $total_amount_other = 0.00;
+    my $due_qr = qr/$due/;
+    # Cycle through the fines and
+    # - find line that relates to the requested $itemnum
+    # - accumulate fines for other items
+    # so we can update $itemnum fine taking in account fine caps
+    while (my $rec = $sth->fetchrow_hashref) {
+        if ($rec->{itemnumber} == $itemnum && $rec->{description} =~ /$due_qr/) {
+            if ($data) {
+                warn "Not a unique accountlines record for item $itemnum borrower $borrowernumber";
+            } else {
+                $data = $rec;
+                next;
+            }
+        }
+        $total_amount_other += $rec->{'amount'};
+    }
+    if (my $maxfine = C4::Context->preference('MaxFine')) {
+        if ($total_amount_other + $amount > $maxfine) {
+            my $new_amount = $maxfine - $total_amount_other;
+            warn "Reducing fine for item $itemnum borrower $borrowernumber from $amount to $new_amount - MaxFine reached";
+            return if $new_amount <= 0.00;
+
+            $amount = $new_amount;
+        }
+    }
 
-    if ( my $data = $sth->fetchrow_hashref ) {
+    if ( $data ) {
 
 		# we're updating an existing fine.  Only modify if amount changed
         # Note that in the current implementation, you cannot pay against an accruing fine
diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl
index 8e5a2d5..03463b9 100755
--- a/admin/smart-rules.pl
+++ b/admin/smart-rules.pl
@@ -101,8 +101,8 @@ elsif ($op eq 'delete-branch-item') {
 # save the values entered
 elsif ($op eq 'add') {
     my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
-    my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
-    my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?  WHERE branchcode=? AND categorycode=? AND itemtype=?");
+    my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
+    my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=?  WHERE branchcode=? AND categorycode=? AND itemtype=?");
     
     my $br = $branch; # branch
     my $bor  = $input->param('categorycode'); # borrower category
@@ -122,14 +122,15 @@ elsif ($op eq 'add') {
     $hardduedate = format_date_in_iso($hardduedate);
     my $hardduedatecompare = $input->param('hardduedatecompare');
     my $rentaldiscount = $input->param('rentaldiscount');
+    my $overduefinescap = $input->param('overduefinescap') || undef;
     $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty";
 
     $sth_search->execute($br,$bor,$cat);
     my $res = $sth_search->fetchrow_hashref();
     if ($res->{total}) {
-        $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount, $br,$bor,$cat);
+        $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat);
     } else {
-        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount);
+        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$overduefinescap);
     }
 } 
 elsif ($op eq "set-branch-defaults") {
diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql
index 12ea9d1..1039740 100644
--- a/installer/data/mysql/kohastructure.sql
+++ b/installer/data/mysql/kohastructure.sql
@@ -996,6 +996,7 @@ CREATE TABLE `issuingrules` (
   `renewalsallowed` smallint(6) NOT NULL default "0",
   `reservesallowed` smallint(6) NOT NULL default "0",
   `branchcode` varchar(10) NOT NULL default '',
+  overduefinescap decimal default NULL,
   PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
   KEY `categorycode` (`categorycode`),
   KEY `itemtype` (`itemtype`)
diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql
index 2ffe2df..4b10e20 100644
--- a/installer/data/mysql/sysprefs.sql
+++ b/installer/data/mysql/sysprefs.sql
@@ -62,7 +62,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
 -- this is selected by the web installer now
 -- INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('marcflavour','MARC21','Define global MARC flavor (MARC21 or UNIMARC) used for character encoding','MARC21|UNIMARC','Choice');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MARCOrgCode','OSt','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','','free');
-INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MaxFine',9999,'Maximum fine a patron can have for a single late return','','Integer');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MaxFine',NULL,'Maximum fine a patron can have for all late returns at one moment. Single item caps are specified in the circulation rules matrix.','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxoutstanding',5,'maximum amount withstanding to be able make holds','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxreserves',50,'Define maximum number of holds a patron can place','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxItemsInSearchResults',20,'Specify the maximum number of items to display for each result on a page of results',NULL,'free');
diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl
index 51a6486..0cab0c5 100755
--- a/installer/data/mysql/updatedatabase.pl
+++ b/installer/data/mysql/updatedatabase.pl
@@ -5307,6 +5307,21 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     SetVersion ($DBversion);
 }
 
+
+
+$DBversion = '3.09.00.XXX';
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    $dbh->do("ALTER TABLE issuingrules ADD overduefinescap decimal DEFAULT NULL");
+    my $maxfine = C4::Context->preference('MaxFine');
+    if ($maxfine && $maxfine < 900) { # an arbitrary value that tells us it's not "some huge value"
+      $dbh->do("UPDATE issuingrules SET overduefinescap=?",undef,$maxfine);
+      $dbh->do("UPDATE systempreferences SET value = NULL WHERE variable = 'MaxFine'");
+    }
+    $dbh->do("UPDATE systempreferences SET explanation = 'Maximum fine a patron can have for all late returns at one moment. Single item caps are specified in the circulation rules matrix.' WHERE variable = 'MaxFine'");
+    print "Upgrade to $DBversion done (Bug 7420 add overduefinescap to circulation matrix)\n";
+    SetVersion ($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 TableExists($table)
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref
index 55b4457..5600874 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref
@@ -74,10 +74,11 @@ Patrons:
                no: "Don't allow"
          - "staff to access a patron's checkout history (it is stored regardless)."
      -
-         - The late fine for a specific checkout will only go up to
+         - The late fine for all checkouts will only go up to
          - pref: MaxFine
            class: currency
          - '[% local_currency %].'
+         - Empty value means no limit. Single item caps are specified in the circulation rules matrix.
      -
          - pref: memberofinstitution
            choices:
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt
index 635051f..dd77946 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt
@@ -78,6 +78,7 @@ for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde
                 <th>Fine amount</th>
                 <th>Fine charging interval</th>
                 <th>Fine grace period (day)</th>
+                <th>Overdue Fines Cap ($)</th>
                 <th>Suspension in days (day)</th>
                 <th>Renewals allowed (count)</th>
                 <th>Holds allowed (count)</th>
@@ -122,6 +123,7 @@ for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde
 							<td>[% rule.fine %]</td>
 							<td>[% rule.chargeperiod %]</td>
 							<td>[% rule.firstremind %]</td>
+							<td>[% rule.overduefinescap FILTER format("%.2f") %]</td>
 							<td>[% rule.finedays %]</td>
 							<td>[% rule.renewalsallowed %]</td>
 							<td>[% rule.reservesallowed %]</td>
@@ -182,6 +184,7 @@ for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde
                     <td><input name="fine" size="4" /></td>
                     <td><input name="chargeperiod" size="2" /></td>
                     <td><input name="firstremind" size="2" /> </td>
+                    <td><input name="overduefinescap" size="6" /> </td>
                     <td><input name="finedays" size="3" /> </td>
                     <td><input name="renewalsallowed" size="2" /></td>
                     <td><input name="reservesallowed" size="2" /></td>
diff --git a/misc/cronjobs/fines.pl b/misc/cronjobs/fines.pl
index 5124f3c..25a8122 100755
--- a/misc/cronjobs/fines.pl
+++ b/misc/cronjobs/fines.pl
@@ -110,7 +110,7 @@ for my $overdue ( @{$overdues} ) {
     }
     ++$counted;
 
-    my ( $amount, $type, $daycounttotal ) =
+    my ( $amount, $type, $unitcounttotal ) =
       CalcFine( $overdue, $borrower->{categorycode},
         $branchcode, $datedue, $today );
 
@@ -131,7 +131,7 @@ for my $overdue ( @{$overdues} ) {
     push @cells,
       map { defined $borrower->{$_} ? $borrower->{$_} : q{} } @borrower_fields;
     push @cells, map { $overdue->{$_} } @item_fields;
-    push @cells, $type, $daycounttotal, $amount;
+    push @cells, $type, $unitcounttotal, $amount;
     say {$fh} join $delim, @cells;
 }
 close $fh;
diff --git a/misc/cronjobs/staticfines.pl b/misc/cronjobs/staticfines.pl
index 35264dc..098fae6 100755
--- a/misc/cronjobs/staticfines.pl
+++ b/misc/cronjobs/staticfines.pl
@@ -176,7 +176,7 @@ for ( my $i = 0 ; $i < scalar(@$data) ; $i++ ) {
     ( $datedue_days <= $today_days ) or next;    # or it's not overdue, right?
 
     $overdueItemsCounted++;
-    my ( $amount, $type, $daycounttotal, $daycount ) = CalcFine( $data->[$i], $borrower->{'categorycode'}, $branchcode, undef, undef, $datedue, $today );
+    my ( $amount, $type, $unitcounttotal, $unitcount ) = CalcFine( $data->[$i], $borrower->{'categorycode'}, $branchcode, undef, undef, $datedue, $today );
 
     # Reassign fine's amount if specified in command-line
     $amount = $catamounts{$borrower->{'categorycode'}} if (defined $catamounts{$borrower->{'categorycode'}});
-- 
1.7.9.5



More information about the Koha-patches mailing list