use Modern::Perl;
use Test::More tests => 17;
+use Test::Warn;
use C4::Context;
use Koha::Database;
use t::lib::Mocks;
use t::lib::TestBuilder;
-use_ok('C4::Overdues');
+use_ok('C4::Overdues', qw( GetOverdueMessageTransportTypes GetBranchcodesWithOverdueRules UpdateFine ));
can_ok('C4::Overdues', 'GetOverdueMessageTransportTypes');
can_ok('C4::Overdues', 'GetBranchcodesWithOverdueRules');
subtest 'UpdateFine tests' => sub {
- plan tests => 68;
+ plan tests => 75;
$schema->storage->txn_begin;
my $checkout1 = $builder->build_object(
{
class => 'Koha::Checkouts',
- value => { itemnumber => $item1->itemnumber }
+ value => { itemnumber => $item1->itemnumber, borrowernumber => $patron->id }
}
);
my $checkout2 = $builder->build_object(
{
class => 'Koha::Checkouts',
- value => { itemnumber => $item2->itemnumber }
+ value => { itemnumber => $item2->itemnumber, borrowernumber => $patron->id }
}
);
$fine = $fines->next;
is( $fine->amount+0, 80, "First fine amount unchanged" );
is( $fine->amountoutstanding+0, 80, "First fine amountoutstanding unchanged" );
- my $fine2 = $fines->next;
+ $fine2 = $fines->next;
is( $fine2->amount+0, 20, "Second fine capped at '20' by MaxFine" );
is( $fine2->amountoutstanding+0, 20, "Second fine amountoutstanding capped at '20' by MaxFine" );
is( $fine2->issue_id, $checkout2->issue_id, "Second fine is associated with the correct issue" );
is( $fine3->amount+0, 30, "Third fine reduced" );
is( $fine3->amountoutstanding+0, 10, "Third fine amount outstanding is reduced" );
+ # Ensure maxfine calculations work correctly for floats (bug #25127)
+ # 7.2 (maxfine) - 7.2 (total_amount_other) != 8.88178419700125e-16 (😢)
+ t::lib::Mocks::mock_preference( 'MaxFine', '7.2' );
+ my $patron_1 = $builder->build_object( { class => 'Koha::Patrons' } );
+ my $item_1 = $builder->build_sample_item();
+ my $item_2 = $builder->build_sample_item();
+ my $checkout_1 = $builder->build_object(
+ {
+ class => 'Koha::Checkouts',
+ value => {
+ itemnumber => $item_1->itemnumber,
+ borrowernumber => $patron_1->id
+ }
+ }
+ );
+ my $checkout_2 = $builder->build_object(
+ {
+ class => 'Koha::Checkouts',
+ value => {
+ itemnumber => $item_2->itemnumber,
+ borrowernumber => $patron->id
+ }
+ }
+ );
+ my $account = $patron_1->account;
+ $account->add_debit(
+ {
+ type => 'OVERDUE',
+ amount => '6.99',
+ issue_id => $checkout_1->issue_id,
+ interface => 'TEST'
+ }
+ );
+ $account->add_debit(
+ {
+ type => 'OVERDUE',
+ amount => '.10',
+ issue_id => $checkout_1->issue_id,
+ interface => 'TEST'
+ }
+ );
+ $account->add_debit(
+ {
+ type => 'OVERDUE',
+ amount => '.10',
+ issue_id => $checkout_1->issue_id,
+ interface => 'TEST'
+ }
+ );
+ $account->add_debit(
+ {
+ type => 'OVERDUE',
+ amount => '.01',
+ issue_id => $checkout_1->issue_id,
+ interface => 'TEST'
+ }
+ );
+ UpdateFine(
+ {
+ issue_id => $checkout_2->issue_id,
+ itemnumber => $item_2->itemnumber,
+ borrowernumber => $patron_1->borrowernumber,
+ amount => '.1',
+ due => $checkout_2->date_due
+ }
+ );
+ $fines = Koha::Account::Lines->search(
+ { borrowernumber => $patron_1->borrowernumber },
+ { order_by => { '-asc' => 'accountlines_id' } }
+ );
+ is( $fines->count, 4, "New amount should be 0 so no fine added" );
+ ok( C4::Circulation::AddReturn( $item_1->barcode, $item_1->homebranch, 1), "Returning the item and forgiving fines succeeds");
+
+ t::lib::Mocks::mock_preference( 'MaxFine', 0 );
+
+ # Ensure CalcFine calculations work correctly for floats (bug #27079)
+ # 1.800000 (amount from database) != 1.8~ (CalcFine of 0.15cents * 12units) (😢)
+ my $amount = 0.15 * 12;
+ UpdateFine(
+ {
+ issue_id => $checkout_2->issue_id,
+ itemnumber => $item_2->itemnumber,
+ borrowernumber => $patron_1->borrowernumber,
+ amount => $amount,
+ due => $checkout_2->date_due
+ }
+ );
+ $fine = Koha::Account::Lines->search({ issue_id => $checkout_2->issue_id })->single;
+ ok( $fine, 'Fine added for checkout 2');
+ is( $fine->amount, "1.800000", "Fine amount is 1.800000 as expected");
+
+ $fine->amountoutstanding(0)->store;
+ $fine->discard_changes;
+ is( $fine->amountoutstanding + 0, 0, "Fine was paid off");
+ UpdateFine(
+ {
+ issue_id => $checkout_2->issue_id,
+ itemnumber => $item_2->itemnumber,
+ borrowernumber => $patron_1->borrowernumber,
+ amount => $amount,
+ due => $checkout_2->date_due
+ }
+ );
+ my $refunds = Koha::Account::Lines->search({ itemnumber => $item_2->itemnumber, credit_type_code => 'OVERPAYMENT' });
+ is( $refunds->count, 0, "Overpayment refund not added when the amounts are equal" );
+
+ # Adding an OVERDUE fine not linked with a checkout (possible with historical OVERDUE fines)
+ $builder->build_object(
+ {
+ class => "Koha::Account::Lines",
+ value => {
+ borrowernumber => $patron_1->borrowernumber,
+ issue_id => undef,
+ debit_type_code => 'OVERDUE',
+ }
+ }
+ );
+ $fine->issue_id(undef)->store;
+ warnings_are {
+ UpdateFine(
+ {
+ issue_id => $checkout_2->issue_id,
+ itemnumber => $item_2->itemnumber,
+ borrowernumber => $patron_1->borrowernumber,
+ amount => $amount,
+ due => $checkout_2->date_due
+ }
+ );
+ } [], 'No warning generated if fine is not linked with a checkout';
+
$schema->storage->txn_rollback;
};