Bug 41267: Add fill_other_biblio_holds_policy circulation rule
This patch adds a new rule for itemtypes to allow/prevent filling other holds on a bibliographic record
The rule will obey ReservesControlBranch for determining the rules
To test:
1 - Apply patches
2 - Setup/choose 2 item types in Administration->Item types
3 - In Administration -> Circulation and fine rules scroll to the bottom
4 - Set one item type to "Fill other holds on record" = 'Yes' and the other to 'No'
5 - Place a next available hold on the record
6 - Checkout the 'Yes' item type to the patron
7 - Their hold should fill
8 - Check in the items
9 - Place a next available hold on the record
10 - Checkout the 'No' itemtype to the patron
11 - Their hold should not be filled
12 - Check in the item and confirm the hold
13 - Checkout the itme to the patron, the hold fills
NOTE: While seemingly counter intuitive, the rule controls whether a hold NOT tied to this item will fill
Confirming the hold adds an itemnumber to the hold. In most cases, these items will not be holdable, so won't trigger at checkin
14 - Set a rule for the patrons branch to No and set system preference ReservesControlBranch to 'Patrons library'
15 - repeat 5&6
16 - The hold should not fill
17 - Change reserves control branch to items home library
18 - checkin /checkout the yes item type
19 - The hold should fill
Signed-off-by: Andrew Auld <andrew.auld@openfifth.co.uk>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
ea4600476e
commit
876869544f
|
|
@ -2144,13 +2144,13 @@ sub MoveReserve {
|
||||||
my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
|
my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
|
||||||
my ( $restype, $res, undef ) = CheckReserves( $item, $lookahead );
|
my ( $restype, $res, undef ) = CheckReserves( $item, $lookahead );
|
||||||
|
|
||||||
|
my $hold;
|
||||||
if ( $res && $res->{borrowernumber} == $patron->borrowernumber ) {
|
if ( $res && $res->{borrowernumber} == $patron->borrowernumber ) {
|
||||||
my $hold = Koha::Holds->find( $res->{reserve_id} );
|
$hold = Koha::Holds->find( $res->{reserve_id} );
|
||||||
$hold->fill( { item_id => $item->id } );
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
# The item is reserved by someone else.
|
# The next reserve is for someone else,
|
||||||
# Find this item in the reserves
|
# Check if this patron has a reserve on this biblio/item
|
||||||
|
|
||||||
my $lookahead_date = output_pref(
|
my $lookahead_date = output_pref(
|
||||||
{
|
{
|
||||||
|
|
@ -2158,7 +2158,7 @@ sub MoveReserve {
|
||||||
dateformat => 'iso', dateonly => 1
|
dateformat => 'iso', dateonly => 1
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
my $hold = $patron->holds->search(
|
$hold = $patron->holds->search(
|
||||||
{
|
{
|
||||||
biblionumber => $item->biblionumber,
|
biblionumber => $item->biblionumber,
|
||||||
reservedate => { '<=' => $lookahead_date },
|
reservedate => { '<=' => $lookahead_date },
|
||||||
|
|
@ -2166,17 +2166,38 @@ sub MoveReserve {
|
||||||
},
|
},
|
||||||
{ order_by => 'priority' }
|
{ order_by => 'priority' }
|
||||||
)->next();
|
)->next();
|
||||||
|
}
|
||||||
|
|
||||||
if ($hold) {
|
if ($hold) {
|
||||||
|
if ( $hold->itemnumber && $hold->itemnumber == $item->id ) {
|
||||||
|
|
||||||
# The item is reserved by the current patron
|
# The item is reserved by the current patron
|
||||||
$hold->fill( { item_id => $item->id } );
|
$hold->fill( { item_id => $item->id } );
|
||||||
}
|
} else {
|
||||||
|
my $controlbranch = $patron->branchcode;
|
||||||
|
if ( C4::Context->preference('ReservesControlBranch') eq 'ItemHomeLibrary' ) {
|
||||||
|
$controlbranch = $item->homebranch;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If no rule is set, the default behavior is to fill the hold
|
||||||
|
my $fill_other_biblio_holds_policy = Koha::CirculationRules->get_effective_rule_value(
|
||||||
|
{
|
||||||
|
categorycode => undef,
|
||||||
|
itemtype => $item->itype,
|
||||||
|
branchcode => $controlbranch,
|
||||||
|
rule_name => 'fill_other_biblio_holds_policy',
|
||||||
|
}
|
||||||
|
) // 1;
|
||||||
|
|
||||||
|
$hold->fill( { item_id => $item->id } ) if $fill_other_biblio_holds_policy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $cancelreserve && $res ) {
|
||||||
$hold = Koha::Holds->find( $res->{reserve_id} );
|
$hold = Koha::Holds->find( $res->{reserve_id} );
|
||||||
if ( $cancelreserve eq 'revert' ) {
|
if ( $cancelreserve eq 'revert' ) {
|
||||||
$hold->revert_found();
|
$hold->revert_found();
|
||||||
} elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
|
} else { # cancel reserves on this item
|
||||||
$hold->cancel;
|
$hold->cancel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ our $RULE_KINDS = {
|
||||||
scope => [ 'branchcode', 'itemtype' ],
|
scope => [ 'branchcode', 'itemtype' ],
|
||||||
can_be_blank => 0,
|
can_be_blank => 0,
|
||||||
},
|
},
|
||||||
|
fill_other_biblio_holds_policy => {
|
||||||
|
scope => [ 'branchcode', 'itemtype' ],
|
||||||
|
can_be_blank => 0,
|
||||||
|
},
|
||||||
returnbranch => {
|
returnbranch => {
|
||||||
scope => [ 'branchcode', 'itemtype' ],
|
scope => [ 'branchcode', 'itemtype' ],
|
||||||
can_be_blank => 0,
|
can_be_blank => 0,
|
||||||
|
|
|
||||||
|
|
@ -214,11 +214,12 @@ if ( $op eq 'cud-delete' ) {
|
||||||
branchcode => $rule_branch,
|
branchcode => $rule_branch,
|
||||||
itemtype => $rule_itemtype,
|
itemtype => $rule_itemtype,
|
||||||
rules => {
|
rules => {
|
||||||
holdallowed => undef,
|
holdallowed => undef,
|
||||||
hold_fulfillment_policy => undef,
|
hold_fulfillment_policy => undef,
|
||||||
bookings_lead_period => undef,
|
fill_other_biblio_holds_policy => undef,
|
||||||
bookings_trail_period => undef,
|
bookings_lead_period => undef,
|
||||||
returnbranch => undef,
|
bookings_trail_period => undef,
|
||||||
|
returnbranch => undef,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -470,12 +471,13 @@ elsif ( $op eq 'cud-add' ) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} elsif ( $op eq "cud-add-branch-item" ) {
|
} elsif ( $op eq "cud-add-branch-item" ) {
|
||||||
my $itemtype = $input->param('itemtype');
|
my $itemtype = $input->param('itemtype');
|
||||||
my $holdallowed = $input->param('holdallowed');
|
my $holdallowed = $input->param('holdallowed');
|
||||||
my $hold_fulfillment_policy = $input->param('hold_fulfillment_policy');
|
my $hold_fulfillment_policy = $input->param('hold_fulfillment_policy');
|
||||||
my $bookings_lead_period = $input->param('bookings_lead_period');
|
my $fill_other_biblio_holds_policy = $input->param('fill_other_biblio_holds_policy');
|
||||||
my $bookings_trail_period = $input->param('bookings_trail_period');
|
my $bookings_lead_period = $input->param('bookings_lead_period');
|
||||||
my $returnbranch = $input->param('returnbranch');
|
my $bookings_trail_period = $input->param('bookings_trail_period');
|
||||||
|
my $returnbranch = $input->param('returnbranch');
|
||||||
|
|
||||||
my $rule_branch = $branch eq '*' ? undef : $branch;
|
my $rule_branch = $branch eq '*' ? undef : $branch;
|
||||||
my $rule_itemtype = $itemtype eq '*' ? undef : $itemtype;
|
my $rule_itemtype = $itemtype eq '*' ? undef : $itemtype;
|
||||||
|
|
@ -485,11 +487,12 @@ elsif ( $op eq 'cud-add' ) {
|
||||||
itemtype => $rule_itemtype,
|
itemtype => $rule_itemtype,
|
||||||
branchcode => $rule_branch,
|
branchcode => $rule_branch,
|
||||||
rules => {
|
rules => {
|
||||||
holdallowed => $holdallowed,
|
holdallowed => $holdallowed,
|
||||||
hold_fulfillment_policy => $hold_fulfillment_policy,
|
hold_fulfillment_policy => $hold_fulfillment_policy,
|
||||||
bookings_lead_period => $bookings_lead_period,
|
fill_other_biblio_holds_policy => $fill_other_biblio_holds_policy,
|
||||||
bookings_trail_period => $bookings_trail_period,
|
bookings_lead_period => $bookings_lead_period,
|
||||||
returnbranch => $returnbranch,
|
bookings_trail_period => $bookings_trail_period,
|
||||||
|
returnbranch => $returnbranch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1379,6 +1379,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Item type</th>
|
<th>Item type</th>
|
||||||
<th>Hold policy</th>
|
<th>Hold policy</th>
|
||||||
|
<th>Fill other holds on record</th>
|
||||||
<th>Hold and booking pickup library match</th>
|
<th>Hold and booking pickup library match</th>
|
||||||
<th>Booking pre-processing (days)</th>
|
<th>Booking pre-processing (days)</th>
|
||||||
<th>Booking post-processing (days)</th>
|
<th>Booking post-processing (days)</th>
|
||||||
|
|
@ -1389,12 +1390,13 @@
|
||||||
[% SET it = i.itemtype %]
|
[% SET it = i.itemtype %]
|
||||||
[% SET c = undef %]
|
[% SET c = undef %]
|
||||||
[% SET holdallowed = all_rules.$c.$it.holdallowed %]
|
[% SET holdallowed = all_rules.$c.$it.holdallowed %]
|
||||||
|
[% SET fill_other_biblio_holds_policy = all_rules.$c.$it.fill_other_biblio_holds_policy %]
|
||||||
[% SET hold_fulfillment_policy = all_rules.$c.$it.hold_fulfillment_policy %]
|
[% SET hold_fulfillment_policy = all_rules.$c.$it.hold_fulfillment_policy %]
|
||||||
[% SET bookings_lead_period = all_rules.$c.$it.bookings_lead_period %]
|
[% SET bookings_lead_period = all_rules.$c.$it.bookings_lead_period %]
|
||||||
[% SET bookings_trail_period = all_rules.$c.$it.bookings_trail_period %]
|
[% SET bookings_trail_period = all_rules.$c.$it.bookings_trail_period %]
|
||||||
[% SET returnbranch = all_rules.$c.$it.returnbranch %]
|
[% SET returnbranch = all_rules.$c.$it.returnbranch %]
|
||||||
|
|
||||||
[% IF holdallowed || hold_fulfillment_policy || returnbranch || bookings_lead_period || bookings_trail_period %]
|
[% IF holdallowed || hold_fulfillment_policy || fill_other_biblio_holds_policy || returnbranch || bookings_lead_period || bookings_trail_period %]
|
||||||
<tr>
|
<tr>
|
||||||
<td> [% i.translated_description | html %] </td>
|
<td> [% i.translated_description | html %] </td>
|
||||||
<td>
|
<td>
|
||||||
|
|
@ -1408,6 +1410,13 @@
|
||||||
<span>No holds allowed</span>
|
<span>No holds allowed</span>
|
||||||
[% END %]
|
[% END %]
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
[% IF fill_other_biblio_holds_policy %]
|
||||||
|
<span> Yes </span>
|
||||||
|
[% ELSE %]
|
||||||
|
<span> No </span>
|
||||||
|
[% END %]
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
[% IF hold_fulfillment_policy == 'any' %]
|
[% IF hold_fulfillment_policy == 'any' %]
|
||||||
<span>any library</span>
|
<span>any library</span>
|
||||||
|
|
@ -1460,6 +1469,12 @@
|
||||||
<option value="not_allowed">No holds allowed</option>
|
<option value="not_allowed">No holds allowed</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<select name="fill_other_biblio_holds_policy">
|
||||||
|
<option value="1" selected="selected"> Yes </option>
|
||||||
|
<option value="0"> No </option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="hold_fulfillment_policy">
|
<select name="hold_fulfillment_policy">
|
||||||
<option value="any"> any library </option>
|
<option value="any"> any library </option>
|
||||||
|
|
|
||||||
|
|
@ -1072,7 +1072,7 @@ subtest 'Hold fee charging tests' => sub {
|
||||||
|
|
||||||
subtest 'MoveReserve additional test' => sub {
|
subtest 'MoveReserve additional test' => sub {
|
||||||
|
|
||||||
plan tests => 8;
|
plan tests => 10;
|
||||||
|
|
||||||
# Create the items and patrons we need
|
# Create the items and patrons we need
|
||||||
my $biblio = $builder->build_sample_biblio();
|
my $biblio = $builder->build_sample_biblio();
|
||||||
|
|
@ -1143,6 +1143,38 @@ subtest 'MoveReserve additional test' => sub {
|
||||||
is( $patron_2->holds->count, 0, "The 2nd patron no longer has a hold" );
|
is( $patron_2->holds->count, 0, "The 2nd patron no longer has a hold" );
|
||||||
is( $patron_2->old_holds->count(), 2, "The 2nd patron's hold was filled and moved to old holds" );
|
is( $patron_2->old_holds->count(), 2, "The 2nd patron's hold was filled and moved to old holds" );
|
||||||
|
|
||||||
|
my $reserve_4 = AddReserve(
|
||||||
|
{
|
||||||
|
branchcode => $item_2->homebranch,
|
||||||
|
borrowernumber => $patron_2->borrowernumber,
|
||||||
|
biblionumber => $biblio->biblionumber,
|
||||||
|
priority => 1,
|
||||||
|
itemnumber => undef,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Koha::CirculationRules->set_rule(
|
||||||
|
{
|
||||||
|
branchcode => $item_1->homebranch,
|
||||||
|
itemtype => $item_1->itype,
|
||||||
|
rule_name => 'fill_other_biblio_holds_policy',
|
||||||
|
rule_value => 0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Koha::CirculationRules->set_rule(
|
||||||
|
{
|
||||||
|
branchcode => $patron_2->branchcode,
|
||||||
|
itemtype => $item_1->itype,
|
||||||
|
rule_name => 'fill_other_biblio_holds_policy',
|
||||||
|
rule_value => 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
|
||||||
|
MoveReserve( $item_1, $patron_2 );
|
||||||
|
is( $patron_2->holds->count, 1, "The hold is not filled because of circ rules" );
|
||||||
|
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
|
||||||
|
MoveReserve( $item_1, $patron_2 );
|
||||||
|
is( $patron_2->holds->count, 0, "The hold is filled because of circ rules and affected by ReservesControlBranch" );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# FIXME: Should be in Circulation.t
|
# FIXME: Should be in Circulation.t
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue