Bug 23012: Set policy for lost item processing fee
Signed-off-by: David Nind <david@davidnind.com> Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
974359ed85
commit
ea8c2959da
4 changed files with 310 additions and 7 deletions
|
@ -51,7 +51,9 @@ our $RULE_KINDS = {
|
||||||
lostreturn => {
|
lostreturn => {
|
||||||
scope => [ 'branchcode' ],
|
scope => [ 'branchcode' ],
|
||||||
},
|
},
|
||||||
|
processingreturn => {
|
||||||
|
scope => [ 'branchcode' ],
|
||||||
|
},
|
||||||
patron_maxissueqty => {
|
patron_maxissueqty => {
|
||||||
scope => [ 'branchcode', 'categorycode' ],
|
scope => [ 'branchcode', 'categorycode' ],
|
||||||
},
|
},
|
||||||
|
@ -617,6 +619,50 @@ sub get_lostreturn_policy {
|
||||||
return $rule ? $rule->rule_value : 'refund';
|
return $rule ? $rule->rule_value : 'refund';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head3 get_processingreturn_policy
|
||||||
|
|
||||||
|
my $processingrefund_policy = Koha::CirculationRules->get_processingreturn_policy( { return_branch => $return_branch, item => $item } );
|
||||||
|
|
||||||
|
Return values are:
|
||||||
|
|
||||||
|
=over 2
|
||||||
|
|
||||||
|
=item '0' - Do not refund
|
||||||
|
|
||||||
|
=item 'refund' - Refund the lost item processing charge
|
||||||
|
|
||||||
|
=item 'restore' - Refund the lost item processing charge and restore the original overdue fine
|
||||||
|
|
||||||
|
=item 'charge' - Refund the lost item processing charge and charge a new overdue fine
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub get_processingreturn_policy {
|
||||||
|
my ( $class, $params ) = @_;
|
||||||
|
|
||||||
|
my $item = $params->{item};
|
||||||
|
|
||||||
|
my $behaviour = C4::Context->preference( 'RefundLostOnReturnControl' ) // 'CheckinLibrary';
|
||||||
|
my $behaviour_mapping = {
|
||||||
|
CheckinLibrary => $params->{'return_branch'} // $item->homebranch,
|
||||||
|
ItemHomeBranch => $item->homebranch,
|
||||||
|
ItemHoldingBranch => $item->holdingbranch
|
||||||
|
};
|
||||||
|
|
||||||
|
my $branch = $behaviour_mapping->{ $behaviour };
|
||||||
|
|
||||||
|
my $rule = Koha::CirculationRules->get_effective_rule(
|
||||||
|
{
|
||||||
|
branchcode => $branch,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $rule ? $rule->rule_value : 'refund';
|
||||||
|
}
|
||||||
|
|
||||||
=head3 article_requestable_rules
|
=head3 article_requestable_rules
|
||||||
|
|
||||||
Return rules that allow article requests, optionally filtered by
|
Return rules that allow article requests, optionally filtered by
|
||||||
|
|
|
@ -654,6 +654,31 @@ elsif ( $op eq 'mod-refund-lost-item-fee-rule' ) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $processingreturn = $input->param('processingreturn');
|
||||||
|
|
||||||
|
if ( $processingreturn eq '*' ) {
|
||||||
|
if ( $branch ne '*' ) {
|
||||||
|
# only do something for $processingreturn eq '*' if branch-specific
|
||||||
|
Koha::CirculationRules->set_rules(
|
||||||
|
{
|
||||||
|
branchcode => $branch,
|
||||||
|
rules => {
|
||||||
|
processingreturn => undef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Koha::CirculationRules->set_rules(
|
||||||
|
{
|
||||||
|
branchcode => $branch,
|
||||||
|
rules => {
|
||||||
|
processingreturn => $processingreturn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
} elsif ( $op eq "set-waiting-hold-cancellation" ) {
|
} elsif ( $op eq "set-waiting-hold-cancellation" ) {
|
||||||
|
|
||||||
my $category = $input->param('waiting_hold_cancellation_category');
|
my $category = $input->param('waiting_hold_cancellation_category');
|
||||||
|
@ -691,9 +716,13 @@ elsif ( $op eq 'mod-refund-lost-item-fee-rule' ) {
|
||||||
|
|
||||||
my $refundLostItemFeeRule = Koha::CirculationRules->find({ branchcode => ($branch eq '*') ? undef : $branch, rule_name => 'lostreturn' });
|
my $refundLostItemFeeRule = Koha::CirculationRules->find({ branchcode => ($branch eq '*') ? undef : $branch, rule_name => 'lostreturn' });
|
||||||
my $defaultLostItemFeeRule = Koha::CirculationRules->find({ branchcode => undef, rule_name => 'lostreturn' });
|
my $defaultLostItemFeeRule = Koha::CirculationRules->find({ branchcode => undef, rule_name => 'lostreturn' });
|
||||||
|
my $refundProcessingFeeRule = Koha::CirculationRules->find({ branchcode => ($branch eq '*') ? undef : $branch, rule_name => 'processingreturn' });
|
||||||
|
my $defaultProcessingFeeRule = Koha::CirculationRules->find({ branchcode => undef, rule_name => 'processingreturn' });
|
||||||
$template->param(
|
$template->param(
|
||||||
refundLostItemFeeRule => $refundLostItemFeeRule,
|
refundLostItemFeeRule => $refundLostItemFeeRule,
|
||||||
defaultRefundRule => $defaultLostItemFeeRule ? $defaultLostItemFeeRule->rule_value : 'refund'
|
defaultRefundRule => $defaultLostItemFeeRule ? $defaultLostItemFeeRule->rule_value : 'refund',
|
||||||
|
refundProcessingFeeRule => $refundProcessingFeeRule,
|
||||||
|
defaultProcessingRefundRule => $defaultProcessingFeeRule ? $defaultProcessingFeeRule->rule_value : 'refund',
|
||||||
);
|
);
|
||||||
|
|
||||||
my $patron_categories = Koha::Patron::Categories->search({}, { order_by => ['description'] });
|
my $patron_categories = Koha::Patron::Categories->search({}, { order_by => ['description'] });
|
||||||
|
|
|
@ -1073,7 +1073,8 @@
|
||||||
<input type="hidden" name="branch" value="[% current_branch | html %]" />
|
<input type="hidden" name="branch" value="[% current_branch | html %]" />
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Refund lost item fee</th>
|
<th>Refund lost item replacement fee</th>
|
||||||
|
<th>Refund lost item processing fee</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1179,6 +1180,64 @@
|
||||||
[% END %]
|
[% END %]
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<select name="processingreturn">
|
||||||
|
[%# Default branch %]
|
||||||
|
[% IF ( current_branch == '*' ) %]
|
||||||
|
[% IF ( defaultProcessingRefundRule == 'refund' ) %]
|
||||||
|
<option value="refund" selected="selected">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% ELSIF ( defaultProcessingRefundRule == 'refund_unpaid' ) %]
|
||||||
|
<option value="refund">Refund lost item charge</option>
|
||||||
|
<option value="refund_unpaid" selected="selected">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% ELSIF ( defaultProcessingRefundRule == 0 ) %]
|
||||||
|
<option value="refund">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0" selected="selected">Leave lost item processing charge</option>
|
||||||
|
[% ELSE %]
|
||||||
|
<option value="refund">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% END %]
|
||||||
|
[% ELSE %]
|
||||||
|
[%# Branch-specific %]
|
||||||
|
[% IF ( not refundProcessingFeeRule ) %]
|
||||||
|
<option value="*" selected="selected">
|
||||||
|
[% ELSE %]
|
||||||
|
<option value="*">
|
||||||
|
[% END %]
|
||||||
|
[% IF defaultProcessingRefundRule == 'refund' %]
|
||||||
|
<span>Use default (Refund lost item processing charge)</span>
|
||||||
|
[% ELSIF defaultProcessingRefundRule == 'refund_unpaid' %]
|
||||||
|
Use default (Refund lost item processing charge (only if unpaid))
|
||||||
|
[% ELSE %]
|
||||||
|
<span>Use default (Leave lost item processing charge)</span>
|
||||||
|
[% END %]
|
||||||
|
</option>
|
||||||
|
[% IF ( not refundProcessingFeeRule ) %]
|
||||||
|
<option value="refund">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% ELSE %]
|
||||||
|
[% IF ( refundProcessingFeeRule.rule_value == 'refund' ) %]
|
||||||
|
<option value="refund" selected="selected">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% ELSIF ( refundProcessingFeeRule.rule_value == 'refund_unpaid' ) %]
|
||||||
|
<option value="refund">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid" selected="selected">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0">Leave lost item processing charge</option>
|
||||||
|
[% ELSIF ( refundProcessingFeeRule.rule_value == 0 ) %]
|
||||||
|
<option value="refund">Refund lost item processing charge</option>
|
||||||
|
<option value="refund_unpaid">Refund lost item processing charge (only if unpaid)</option>
|
||||||
|
<option value="0" selected="selected">Leave lost item processing charge</option>
|
||||||
|
[% END %]
|
||||||
|
[% END %]
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
<button type="submit" class="btn btn-default btn-xs"><i class="fa fa-save"></i> Save</button>
|
<button type="submit" class="btn btn-default btn-xs"><i class="fa fa-save"></i> Save</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use Modern::Perl;
|
use Modern::Perl;
|
||||||
|
|
||||||
use Benchmark;
|
use Benchmark;
|
||||||
use Test::More tests => 7;
|
use Test::More tests => 8;
|
||||||
use Test::Deep qw( cmp_methods );
|
use Test::Deep qw( cmp_methods );
|
||||||
use Test::Exception;
|
use Test::Exception;
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ subtest 'set_rule' => sub {
|
||||||
my $itemtype = $builder->build({ source => 'Itemtype' })->{'itemtype'};
|
my $itemtype = $builder->build({ source => 'Itemtype' })->{'itemtype'};
|
||||||
|
|
||||||
subtest 'Correct call' => sub {
|
subtest 'Correct call' => sub {
|
||||||
plan tests => 4;
|
plan tests => 5;
|
||||||
|
|
||||||
Koha::CirculationRules->delete;
|
Koha::CirculationRules->delete;
|
||||||
|
|
||||||
|
@ -173,6 +173,14 @@ subtest 'set_rule' => sub {
|
||||||
} );
|
} );
|
||||||
}, 'setting lostreturn with branch' );
|
}, 'setting lostreturn with branch' );
|
||||||
|
|
||||||
|
lives_ok( sub {
|
||||||
|
Koha::CirculationRules->set_rule( {
|
||||||
|
branchcode => $branchcode,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => '',
|
||||||
|
} );
|
||||||
|
}, 'setting processingreturn with branch' );
|
||||||
|
|
||||||
lives_ok( sub {
|
lives_ok( sub {
|
||||||
Koha::CirculationRules->set_rule( {
|
Koha::CirculationRules->set_rule( {
|
||||||
branchcode => $branchcode,
|
branchcode => $branchcode,
|
||||||
|
@ -203,7 +211,7 @@ subtest 'set_rule' => sub {
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest 'Call with missing params' => sub {
|
subtest 'Call with missing params' => sub {
|
||||||
plan tests => 4;
|
plan tests => 5;
|
||||||
|
|
||||||
Koha::CirculationRules->delete;
|
Koha::CirculationRules->delete;
|
||||||
|
|
||||||
|
@ -214,6 +222,13 @@ subtest 'set_rule' => sub {
|
||||||
} );
|
} );
|
||||||
}, qr/branchcode/, 'setting lostreturn without branch fails' );
|
}, qr/branchcode/, 'setting lostreturn without branch fails' );
|
||||||
|
|
||||||
|
throws_ok( sub {
|
||||||
|
Koha::CirculationRules->set_rule( {
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => '',
|
||||||
|
} );
|
||||||
|
}, qr/branchcode/, 'setting processingreturn without branch fails' );
|
||||||
|
|
||||||
throws_ok( sub {
|
throws_ok( sub {
|
||||||
Koha::CirculationRules->set_rule( {
|
Koha::CirculationRules->set_rule( {
|
||||||
branchcode => $branchcode,
|
branchcode => $branchcode,
|
||||||
|
@ -241,7 +256,7 @@ subtest 'set_rule' => sub {
|
||||||
};
|
};
|
||||||
|
|
||||||
subtest 'Call with extra params' => sub {
|
subtest 'Call with extra params' => sub {
|
||||||
plan tests => 3;
|
plan tests => 4;
|
||||||
|
|
||||||
Koha::CirculationRules->delete;
|
Koha::CirculationRules->delete;
|
||||||
|
|
||||||
|
@ -254,6 +269,15 @@ subtest 'set_rule' => sub {
|
||||||
} );
|
} );
|
||||||
}, qr/categorycode/, 'setting lostreturn with categorycode fails' );
|
}, qr/categorycode/, 'setting lostreturn with categorycode fails' );
|
||||||
|
|
||||||
|
throws_ok( sub {
|
||||||
|
Koha::CirculationRules->set_rule( {
|
||||||
|
branchcode => $branchcode,
|
||||||
|
categorycode => $categorycode,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => '',
|
||||||
|
} );
|
||||||
|
}, qr/categorycode/, 'setting processingreturn with categorycode fails' );
|
||||||
|
|
||||||
throws_ok( sub {
|
throws_ok( sub {
|
||||||
Koha::CirculationRules->set_rule( {
|
Koha::CirculationRules->set_rule( {
|
||||||
branchcode => $branchcode,
|
branchcode => $branchcode,
|
||||||
|
@ -801,6 +825,151 @@ subtest 'get_lostreturn_policy() tests' => sub {
|
||||||
$schema->storage->txn_rollback;
|
$schema->storage->txn_rollback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subtest 'get_processingreturn_policy() tests' => sub {
|
||||||
|
plan tests => 7;
|
||||||
|
|
||||||
|
$schema->storage->txn_begin;
|
||||||
|
|
||||||
|
$schema->resultset('CirculationRule')->search()->delete;
|
||||||
|
|
||||||
|
my $default_rule_charge = $builder->build(
|
||||||
|
{
|
||||||
|
source => 'CirculationRule',
|
||||||
|
value => {
|
||||||
|
branchcode => undef,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 'charge'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
|
||||||
|
my $specific_rule_false = $builder->build(
|
||||||
|
{
|
||||||
|
source => 'CirculationRule',
|
||||||
|
value => {
|
||||||
|
branchcode => $branchcode,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
my $branchcode2 = $builder->build( { source => 'Branch' } )->{branchcode};
|
||||||
|
my $specific_rule_refund = $builder->build(
|
||||||
|
{
|
||||||
|
source => 'CirculationRule',
|
||||||
|
value => {
|
||||||
|
branchcode => $branchcode2,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 'refund'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
my $branchcode3 = $builder->build( { source => 'Branch' } )->{branchcode};
|
||||||
|
my $specific_rule_restore = $builder->build(
|
||||||
|
{
|
||||||
|
source => 'CirculationRule',
|
||||||
|
value => {
|
||||||
|
branchcode => $branchcode3,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 'restore'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
# Make sure we have an unused branchcode
|
||||||
|
my $branchcode4 = $builder->build( { source => 'Branch' } )->{branchcode};
|
||||||
|
my $specific_rule_dummy = $builder->build(
|
||||||
|
{
|
||||||
|
source => 'CirculationRule',
|
||||||
|
value => {
|
||||||
|
branchcode => $branchcode4,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 'refund'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
my $branch_without_rule = $specific_rule_dummy->{ branchcode };
|
||||||
|
Koha::CirculationRules
|
||||||
|
->search(
|
||||||
|
{
|
||||||
|
branchcode => $branch_without_rule,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn',
|
||||||
|
rule_value => 'refund'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->next
|
||||||
|
->delete;
|
||||||
|
|
||||||
|
my $item = $builder->build_sample_item(
|
||||||
|
{
|
||||||
|
homebranch => $specific_rule_restore->{branchcode},
|
||||||
|
holdingbranch => $specific_rule_false->{branchcode}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
my $params = {
|
||||||
|
return_branch => $specific_rule_refund->{ branchcode },
|
||||||
|
item => $item
|
||||||
|
};
|
||||||
|
|
||||||
|
# Specific rules
|
||||||
|
t::lib::Mocks::mock_preference( 'RefundLostOnReturnControl', 'CheckinLibrary' );
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
'refund','Specific rule for checkin branch is applied (refund)');
|
||||||
|
|
||||||
|
t::lib::Mocks::mock_preference( 'RefundLostOnReturnControl', 'ItemHomeBranch' );
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
'restore','Specific rule for home branch is applied (restore)');
|
||||||
|
|
||||||
|
t::lib::Mocks::mock_preference( 'RefundLostOnReturnControl', 'ItemHoldingBranch' );
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
0,'Specific rule for holding branch is applied (false)');
|
||||||
|
|
||||||
|
# Default rule check
|
||||||
|
t::lib::Mocks::mock_preference( 'RefundLostOnReturnControl', 'CheckinLibrary' );
|
||||||
|
$params->{return_branch} = $branch_without_rule;
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
'charge','No rule for branch, global rule applied (charge)');
|
||||||
|
|
||||||
|
# Change the default value just to try
|
||||||
|
Koha::CirculationRules->search({ branchcode => undef, rule_name => 'processingreturn' })->next->rule_value(0)->store;
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
0,'No rule for branch, global rule applied (false)');
|
||||||
|
|
||||||
|
# No default rule defined check
|
||||||
|
Koha::CirculationRules
|
||||||
|
->search(
|
||||||
|
{
|
||||||
|
branchcode => undef,
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => undef,
|
||||||
|
rule_name => 'processingreturn'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->next
|
||||||
|
->delete;
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
'refund','No rule for branch, no default rule, fallback default (refund)');
|
||||||
|
|
||||||
|
# Fallback to ItemHoldBranch if CheckinLibrary is undefined
|
||||||
|
$params->{return_branch} = undef;
|
||||||
|
is( Koha::CirculationRules->get_processingreturn_policy( $params ),
|
||||||
|
'restore','return_branch undefined, fallback to ItemHomeBranch rule (restore)');
|
||||||
|
|
||||||
|
$schema->storage->txn_rollback;
|
||||||
|
};
|
||||||
|
|
||||||
sub _is_row_match {
|
sub _is_row_match {
|
||||||
my ( $rule, $expected, $message ) = @_;
|
my ( $rule, $expected, $message ) = @_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue