From aa6117da3682230cfe6fe43ee3b29fdb71c74a5a Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Mon, 12 May 2014 12:31:11 +0200 Subject: [PATCH] Bug 12230: Set a maximum suspension days as a new issuing rule This patch adds a new issuing rule: maxsuspensiondays. A new column "Max. suspension duration (day)" appears in the main table of the issuing rules. If this value is filled, on returning an item, a patron won't be suspended longer than this cap. Test plan: 1/ Set "suspension in days" to 2. 2/ Check an item out to a patron and specify a due date to today - 10 days. 3/ Check the item in and verify the patron is suspended until today + 10 * 2 days. 4/ Remove the suspension. 5/ Set "Max. suspension duration" to 10. 6/ Check an item out to a patron and specify a due date to today - 10 days. 7/ Check the item in and verify the patron is suspended until today + 10 days. Signed-off-by: Paola Rossi Signed-off-by: Kyle M Hall Signed-off-by: Galen Charlton --- C4/Circulation.pm | 13 ++- admin/smart-rules.pl | 9 +- .../prog/en/modules/admin/smart-rules.tt | 3 + .../IssuingRules/maxsuspensiondays.t | 87 +++++++++++++++++++ 4 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 639956b51a..6d3347f532 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2085,10 +2085,21 @@ sub _debar_user_on_return { # grace period is measured in the same units as the loan my $grace = DateTime::Duration->new( $unit => $issuingrule->{firstremind} ); + if ( $deltadays->subtract($grace)->is_positive() ) { + my $suspension_days = $deltadays * $finedays; + + # If the max suspension days is < than the suspension days + # the suspension days is limited to this maximum period. + my $max_sd = $issuingrule->{maxsuspensiondays}; + if ( defined $max_sd ) { + $max_sd = DateTime::Duration->new( days => $max_sd ); + $suspension_days = $max_sd + if DateTime::Duration->compare( $max_sd, $suspension_days ) < 0; + } my $new_debar_dt = - $dt_today->clone()->add_duration( $deltadays * $finedays ); + $dt_today->clone()->add_duration( $suspension_days ); Koha::Borrower::Debarments::AddUniqueDebarment({ borrowernumber => $borrower->{borrowernumber}, diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl index 456e7384ca..c6692cb9b8 100755 --- a/admin/smart-rules.pl +++ b/admin/smart-rules.pl @@ -101,14 +101,15 @@ 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, renewalperiod, norenewalbefore, 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=?, renewalperiod=?, norenewalbefore=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); + my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, renewalperiod, norenewalbefore, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, maxsuspensiondays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); + my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, maxsuspensiondays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, renewalperiod=?, norenewalbefore=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); my $br = $branch; # branch my $bor = $input->param('categorycode'); # borrower category my $cat = $input->param('itemtype'); # item type my $fine = $input->param('fine'); my $finedays = $input->param('finedays'); + my $maxsuspensiondays = $input->param('maxsuspensiondays'); my $firstremind = $input->param('firstremind'); my $chargeperiod = $input->param('chargeperiod'); my $maxissueqty = $input->param('maxissueqty'); @@ -131,9 +132,9 @@ elsif ($op eq 'add') { $sth_search->execute($br,$bor,$cat); my $res = $sth_search->fetchrow_hashref(); if ($res->{total}) { - $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat); + $sth_update->execute($fine, $finedays, $maxsuspensiondays, $firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat); } else { - $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$overduefinescap); + $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays, $maxsuspensiondays, $firstremind,$chargeperiod,$rentaldiscount,$overduefinescap); } } elsif ($op eq "set-branch-defaults") { 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 7f2611f8ab..a7fe76e203 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 @@ -148,6 +148,7 @@ for="tobranch">Clone these rules to: Clone these rules to: [% rule.finedays %] + [% rule.maxsuspensiondays %] [% rule.renewalsallowed %] [% rule.renewalperiod %] [% rule.norenewalbefore %] @@ -256,6 +258,7 @@ for="tobranch">Clone these rules to: + diff --git a/t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t b/t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t new file mode 100644 index 0000000000..8c7085a0a8 --- /dev/null +++ b/t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t @@ -0,0 +1,87 @@ +use Modern::Perl; +use Test::More tests => 2; + +use MARC::Record; +use MARC::Field; +use Test::MockModule; +use C4::Context; + +use C4::Biblio qw( AddBiblio ); +use C4::Circulation qw( AddIssue AddReturn ); +use C4::Items qw( AddItem ); +use C4::Members qw( AddMember GetMember ); +use Koha::DateUtils; +use Koha::Borrower::Debarments qw( GetDebarments DelDebarment ); +my $dbh = C4::Context->dbh; +$dbh->{RaiseError} = 1; +$dbh->{AutoCommit} = 0; + +my $branchcode = 'CPL'; +local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /redefined/ }; +my $userenv->{branch} = $branchcode; +*C4::Context::userenv = \&Mock_userenv; + +my $circulation_module = Test::MockModule->new('C4::Circulation'); + +# Test without maxsuspensiondays set +$circulation_module->mock('GetIssuingRule', sub { + return { + firstremind => 0, + finedays => 2, + lengthunit => 'days', + } +}); + +my $borrowernumber = AddMember( + firstname => 'my firstname', + surname => 'my surname', + categorycode => 'S', + branchcode => $branchcode, +); +my $borrower = GetMember( borrowernumber => $borrowernumber ); + +my $record = MARC::Record->new(); +$record->append_fields( + MARC::Field->new('100', ' ', ' ', a => 'My author'), + MARC::Field->new('245', ' ', ' ', a => 'My title'), +); + +my $barcode = 'bc_maxsuspensiondays'; +my ($biblionumber, $biblioitemnumber) = AddBiblio($record, ''); +my (undef, undef, $itemnumber) = AddItem({ + homebranch => $branchcode, + holdingbranch => $branchcode, + barcode => $barcode, + } , $biblionumber); + + +my $daysago20 = dt_from_string->add_duration(DateTime::Duration->new(days => -20)); +my $daysafter40 = dt_from_string->add_duration(DateTime::Duration->new(days => 40)); + +AddIssue( $borrower, $barcode, $daysago20 ); +AddReturn( $barcode, $branchcode ); +my $debarments = GetDebarments({borrowernumber => $borrower->{borrowernumber}}); +is( $debarments->[0]->{expiration}, output_pref({ dt => $daysafter40, dateformat => 'iso', dateonly => 1 })); +DelDebarment( $debarments->[0]->{borrower_debarment_id} ); + +# Test with maxsuspensiondays = 10 days +$circulation_module->mock('GetIssuingRule', sub { + return { + firstremind => 0, + finedays => 2, + maxsuspensiondays => 10, + lengthunit => 'days', + } +}); +my $daysafter10 = dt_from_string->add_duration(DateTime::Duration->new(days => 10)); +AddIssue( $borrower, $barcode, $daysago20 ); +AddReturn( $barcode, $branchcode ); +$debarments = GetDebarments({borrowernumber => $borrower->{borrowernumber}}); +is( $debarments->[0]->{expiration}, output_pref({ dt => $daysafter10, dateformat => 'iso', dateonly => 1 })); +DelDebarment( $debarments->[0]->{borrower_debarment_id} ); + + +# C4::Context->userenv +sub Mock_userenv { + return $userenv; +} -- 2.39.5