View | Details | Raw Unified | Return to bug 7420
Collapse All | Expand All

(-)a/C4/Circulation.pm (-1 / +1 lines)
Lines 1615-1621 sub AddReturn { Link Here
1615
1615
1616
        if ($borrowernumber) {
1616
        if ($borrowernumber) {
1617
        if($issue->{'overdue'}){
1617
        if($issue->{'overdue'}){
1618
                my ( $amount, $type, $daycounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today );
1618
                my ( $amount, $type, $unitcounttotal ) = C4::Overdues::CalcFine( $item, $borrower->{categorycode},$branch, $datedue, $today );
1619
                $type ||= q{};
1619
                $type ||= q{};
1620
        if ( $amount > 0 && ( C4::Context->preference('finesMode') eq 'production' )) {
1620
        if ( $amount > 0 && ( C4::Context->preference('finesMode') eq 'production' )) {
1621
          C4::Overdues::UpdateFine(
1621
          C4::Overdues::UpdateFine(
(-)a/C4/Overdues.pm (-12 / +36 lines)
Lines 241-248 C<$amount> is the fine owed by the patron (see above). Link Here
241
C<$chargename> is the chargename field from the applicable record in
241
C<$chargename> is the chargename field from the applicable record in
242
the categoryitem table, whatever that is.
242
the categoryitem table, whatever that is.
243
243
244
C<$daycount> is the number of days between start and end dates, Calendar adjusted (where needed), 
244
C<$unitcount> is the number of chargeable units (days between start and end dates, Calendar adjusted where needed, 
245
minus any applicable grace period.
245
minus any applicable grace period, or hours)
246
246
247
FIXME - What is chargename supposed to be ?
247
FIXME - What is chargename supposed to be ?
248
248
Lines 268-277 sub CalcFine { Link Here
268
    } else {
268
    } else {
269
        # a zero (or null)  chargeperiod means no charge.
269
        # a zero (or null)  chargeperiod means no charge.
270
    }
270
    }
271
    if(C4::Context->preference('maxFine') && ( $amount > C4::Context->preference('maxFine'))) {
271
    $amount = $data->{overduefinescap} if $data->{overduefinescap} && $amount > $data->{overduefinescap};
272
        $amount = C4::Context->preference('maxFine');
272
    $debug and warn sprintf("CalcFine returning (%s, %s, %s, %s)", $amount, $data->{'chargename'}, $units_minus_grace, $chargeable_units);
273
    }
273
    return ($amount, $data->{'chargename'}, $units_minus_grace, $chargeable_units);
274
    return ($amount, $data->{chargename}, $units_minus_grace);
275
    # FIXME: chargename is NEVER populated anywhere.
274
    # FIXME: chargename is NEVER populated anywhere.
276
}
275
}
277
276
Lines 521-534 sub UpdateFine { Link Here
521
	#   "REF" is Cash Refund
520
	#   "REF" is Cash Refund
522
    my $sth = $dbh->prepare(
521
    my $sth = $dbh->prepare(
523
        "SELECT * FROM accountlines
522
        "SELECT * FROM accountlines
524
		WHERE itemnumber=?
523
		WHERE borrowernumber=?
525
		AND   borrowernumber=?
524
		AND   accounttype IN ('FU','O','F','M')"
526
		AND   accounttype IN ('FU','O','F','M')
527
		AND   description like ? "
528
    );
525
    );
529
    $sth->execute( $itemnum, $borrowernumber, "%$due%" );
526
    $sth->execute( $borrowernumber );
527
    my $data;
528
    my $total_amount_other = 0.00;
529
    my $due_qr = qr/$due/;
530
    # Cycle through the fines and
531
    # - find line that relates to the requested $itemnum
532
    # - accumulate fines for other items
533
    # so we can update $itemnum fine taking in account fine caps
534
    while (my $rec = $sth->fetchrow_hashref) {
535
        if ($rec->{itemnumber} == $itemnum && $rec->{description} =~ /$due_qr/) {
536
            if ($data) {
537
                warn "Not a unique accountlines record for item $itemnum borrower $borrowernumber";
538
            } else {
539
                $data = $rec;
540
                next;
541
            }
542
        }
543
        $total_amount_other += $rec->{'amount'};
544
    }
545
    if (my $maxfine = C4::Context->preference('MaxFine')) {
546
        if ($total_amount_other + $amount > $maxfine) {
547
            my $new_amount = $maxfine - $total_amount_other;
548
            warn "Reducing fine for item $itemnum borrower $borrowernumber from $amount to $new_amount - MaxFine reached";
549
            return if $new_amount <= 0.00;
550
551
            $amount = $new_amount;
552
        }
553
    }
530
554
531
    if ( my $data = $sth->fetchrow_hashref ) {
555
    if ( $data ) {
532
556
533
		# we're updating an existing fine.  Only modify if amount changed
557
		# we're updating an existing fine.  Only modify if amount changed
534
        # Note that in the current implementation, you cannot pay against an accruing fine
558
        # Note that in the current implementation, you cannot pay against an accruing fine
(-)a/admin/smart-rules.pl (-4 / +5 lines)
Lines 101-108 elsif ($op eq 'delete-branch-item') { Link Here
101
# save the values entered
101
# save the values entered
102
elsif ($op eq 'add') {
102
elsif ($op eq 'add') {
103
    my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
103
    my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
104
    my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
104
    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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
105
    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=?");
105
    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=?");
106
    
106
    
107
    my $br = $branch; # branch
107
    my $br = $branch; # branch
108
    my $bor  = $input->param('categorycode'); # borrower category
108
    my $bor  = $input->param('categorycode'); # borrower category
Lines 122-135 elsif ($op eq 'add') { Link Here
122
    $hardduedate = format_date_in_iso($hardduedate);
122
    $hardduedate = format_date_in_iso($hardduedate);
123
    my $hardduedatecompare = $input->param('hardduedatecompare');
123
    my $hardduedatecompare = $input->param('hardduedatecompare');
124
    my $rentaldiscount = $input->param('rentaldiscount');
124
    my $rentaldiscount = $input->param('rentaldiscount');
125
    my $overduefinescap = $input->param('overduefinescap') || undef;
125
    $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty";
126
    $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty";
126
127
127
    $sth_search->execute($br,$bor,$cat);
128
    $sth_search->execute($br,$bor,$cat);
128
    my $res = $sth_search->fetchrow_hashref();
129
    my $res = $sth_search->fetchrow_hashref();
129
    if ($res->{total}) {
130
    if ($res->{total}) {
130
        $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount, $br,$bor,$cat);
131
        $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat);
131
    } else {
132
    } else {
132
        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount);
133
        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$overduefinescap);
133
    }
134
    }
134
} 
135
} 
135
elsif ($op eq "set-branch-defaults") {
136
elsif ($op eq "set-branch-defaults") {
(-)a/installer/data/mysql/kohastructure.sql (+1 lines)
Lines 996-1001 CREATE TABLE `issuingrules` ( Link Here
996
  `renewalsallowed` smallint(6) NOT NULL default "0",
996
  `renewalsallowed` smallint(6) NOT NULL default "0",
997
  `reservesallowed` smallint(6) NOT NULL default "0",
997
  `reservesallowed` smallint(6) NOT NULL default "0",
998
  `branchcode` varchar(10) NOT NULL default '',
998
  `branchcode` varchar(10) NOT NULL default '',
999
  overduefinescap decimal default NULL,
999
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
1000
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
1000
  KEY `categorycode` (`categorycode`),
1001
  KEY `categorycode` (`categorycode`),
1001
  KEY `itemtype` (`itemtype`)
1002
  KEY `itemtype` (`itemtype`)
(-)a/installer/data/mysql/sysprefs.sql (-1 / +1 lines)
Lines 62-68 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
62
-- this is selected by the web installer now
62
-- this is selected by the web installer now
63
-- 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');
63
-- 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');
64
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MARCOrgCode','OSt','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','','free');
64
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MARCOrgCode','OSt','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','','free');
65
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MaxFine',9999,'Maximum fine a patron can have for a single late return','','Integer');
65
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');
66
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxoutstanding',5,'maximum amount withstanding to be able make holds','','Integer');
66
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxoutstanding',5,'maximum amount withstanding to be able make holds','','Integer');
67
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxreserves',50,'Define maximum number of holds a patron can place','','Integer');
67
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxreserves',50,'Define maximum number of holds a patron can place','','Integer');
68
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');
68
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');
(-)a/installer/data/mysql/updatedatabase.pl (+15 lines)
Lines 5307-5312 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
5307
    SetVersion ($DBversion);
5307
    SetVersion ($DBversion);
5308
}
5308
}
5309
5309
5310
5311
5312
$DBversion = '3.09.00.XXX';
5313
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
5314
    $dbh->do("ALTER TABLE issuingrules ADD overduefinescap decimal DEFAULT NULL");
5315
    my $maxfine = C4::Context->preference('MaxFine');
5316
    if ($maxfine && $maxfine < 900) { # an arbitrary value that tells us it's not "some huge value"
5317
      $dbh->do("UPDATE issuingrules SET overduefinescap=?",undef,$maxfine);
5318
      $dbh->do("UPDATE systempreferences SET value = NULL WHERE variable = 'MaxFine'");
5319
    }
5320
    $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'");
5321
    print "Upgrade to $DBversion done (Bug 7420 add overduefinescap to circulation matrix)\n";
5322
    SetVersion ($DBversion);
5323
}
5324
5310
=head1 FUNCTIONS
5325
=head1 FUNCTIONS
5311
5326
5312
=head2 TableExists($table)
5327
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (-1 / +2 lines)
Lines 74-83 Patrons: Link Here
74
               no: "Don't allow"
74
               no: "Don't allow"
75
         - "staff to access a patron's checkout history (it is stored regardless)."
75
         - "staff to access a patron's checkout history (it is stored regardless)."
76
     -
76
     -
77
         - The late fine for a specific checkout will only go up to
77
         - The late fine for all checkouts will only go up to
78
         - pref: MaxFine
78
         - pref: MaxFine
79
           class: currency
79
           class: currency
80
         - '[% local_currency %].'
80
         - '[% local_currency %].'
81
         - Empty value means no limit. Single item caps are specified in the circulation rules matrix.
81
     -
82
     -
82
         - pref: memberofinstitution
83
         - pref: memberofinstitution
83
           choices:
84
           choices:
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (+3 lines)
Lines 78-83 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
78
                <th>Fine amount</th>
78
                <th>Fine amount</th>
79
                <th>Fine charging interval</th>
79
                <th>Fine charging interval</th>
80
                <th>Fine grace period (day)</th>
80
                <th>Fine grace period (day)</th>
81
                <th>Overdue Fines Cap ($)</th>
81
                <th>Suspension in days (day)</th>
82
                <th>Suspension in days (day)</th>
82
                <th>Renewals allowed (count)</th>
83
                <th>Renewals allowed (count)</th>
83
                <th>Holds allowed (count)</th>
84
                <th>Holds allowed (count)</th>
Lines 122-127 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
122
							<td>[% rule.fine %]</td>
123
							<td>[% rule.fine %]</td>
123
							<td>[% rule.chargeperiod %]</td>
124
							<td>[% rule.chargeperiod %]</td>
124
							<td>[% rule.firstremind %]</td>
125
							<td>[% rule.firstremind %]</td>
126
							<td>[% rule.overduefinescap FILTER format("%.2f") %]</td>
125
							<td>[% rule.finedays %]</td>
127
							<td>[% rule.finedays %]</td>
126
							<td>[% rule.renewalsallowed %]</td>
128
							<td>[% rule.renewalsallowed %]</td>
127
							<td>[% rule.reservesallowed %]</td>
129
							<td>[% rule.reservesallowed %]</td>
Lines 182-187 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
182
                    <td><input name="fine" size="4" /></td>
184
                    <td><input name="fine" size="4" /></td>
183
                    <td><input name="chargeperiod" size="2" /></td>
185
                    <td><input name="chargeperiod" size="2" /></td>
184
                    <td><input name="firstremind" size="2" /> </td>
186
                    <td><input name="firstremind" size="2" /> </td>
187
                    <td><input name="overduefinescap" size="6" /> </td>
185
                    <td><input name="finedays" size="3" /> </td>
188
                    <td><input name="finedays" size="3" /> </td>
186
                    <td><input name="renewalsallowed" size="2" /></td>
189
                    <td><input name="renewalsallowed" size="2" /></td>
187
                    <td><input name="reservesallowed" size="2" /></td>
190
                    <td><input name="reservesallowed" size="2" /></td>
(-)a/misc/cronjobs/fines.pl (-2 / +2 lines)
Lines 110-116 for my $overdue ( @{$overdues} ) { Link Here
110
    }
110
    }
111
    ++$counted;
111
    ++$counted;
112
112
113
    my ( $amount, $type, $daycounttotal ) =
113
    my ( $amount, $type, $unitcounttotal ) =
114
      CalcFine( $overdue, $borrower->{categorycode},
114
      CalcFine( $overdue, $borrower->{categorycode},
115
        $branchcode, $datedue, $today );
115
        $branchcode, $datedue, $today );
116
116
Lines 131-137 for my $overdue ( @{$overdues} ) { Link Here
131
    push @cells,
131
    push @cells,
132
      map { defined $borrower->{$_} ? $borrower->{$_} : q{} } @borrower_fields;
132
      map { defined $borrower->{$_} ? $borrower->{$_} : q{} } @borrower_fields;
133
    push @cells, map { $overdue->{$_} } @item_fields;
133
    push @cells, map { $overdue->{$_} } @item_fields;
134
    push @cells, $type, $daycounttotal, $amount;
134
    push @cells, $type, $unitcounttotal, $amount;
135
    say {$fh} join $delim, @cells;
135
    say {$fh} join $delim, @cells;
136
}
136
}
137
close $fh;
137
close $fh;
(-)a/misc/cronjobs/staticfines.pl (-2 / +1 lines)
Lines 176-182 for ( my $i = 0 ; $i < scalar(@$data) ; $i++ ) { Link Here
176
    ( $datedue_days <= $today_days ) or next;    # or it's not overdue, right?
176
    ( $datedue_days <= $today_days ) or next;    # or it's not overdue, right?
177
177
178
    $overdueItemsCounted++;
178
    $overdueItemsCounted++;
179
    my ( $amount, $type, $daycounttotal, $daycount ) = CalcFine( $data->[$i], $borrower->{'categorycode'}, $branchcode, undef, undef, $datedue, $today );
179
    my ( $amount, $type, $unitcounttotal, $unitcount ) = CalcFine( $data->[$i], $borrower->{'categorycode'}, $branchcode, undef, undef, $datedue, $today );
180
180
181
    # Reassign fine's amount if specified in command-line
181
    # Reassign fine's amount if specified in command-line
182
    $amount = $catamounts{$borrower->{'categorycode'}} if (defined $catamounts{$borrower->{'categorycode'}});
182
    $amount = $catamounts{$borrower->{'categorycode'}} if (defined $catamounts{$borrower->{'categorycode'}});
183
- 

Return to bug 7420