Bug 8367: Add holds_pickup_period circulation rule
So that pickup delay can have a different value per patron category, item type or branch. To test: 1) Update database, restart services 2) Set ReservesMaxPickUpDelay syspref (if not already set) 3) Edit your circulation rules and set a value under 'Holds pickup period (day) that is DIFFERENT from ReservesMaxPickUpDelay. Set a few different numbers for different branches as well. 4) Place a hold on a biblio from the staff client. 5) Check in an item from that biblio and confirm the hold as waiting 6) Confirm the expiration date is calculated using the 'Holds pickup period' value instead of the ReservesMaxPickUpDelay syspref 7) Revert the waiting status and delete the hold 8) Re-place the hold on the biblio on the OPAC. Notice that when you change the pick up location, the number of days in the pickup message below the dropdown changes based on the circ rules. 9) Create a holiday with a date that will overlap with the 'Holds pickup period' 10) Check in an item from that biblio and confirm the hold as waiting 11) Confirm the expiration date is calculated using the 'Holds pickup period' value AND considers the special holiday 12) Confirm tests pass t/db_dependent/Holds/WaitingReserves.t 13) Test Talking Tech: 13a) Enable TalkingTechItivaPhoneNotification 13b) Go to Tools -> Notices & slips. Add content to the HOLD phone (itiva) notice. 13c) In your terminal, run perl /path/to/koha/misc/cronjobs/thirdparty/TalkingTech_itiva_outbound.pl -o ~/itiva.tmp -w 0 --type=RESERVE Sponsored-by: Catalyst IT Signed-off-by: Emmi Takkinen <emmi.takkinen@koha-suomi.fi> Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Kelly <kelly@bywatersolutions.com> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Kelly <kelly@bywatersolutions.com> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
c100eda1bd
commit
6c0eb32a08
10 changed files with 178 additions and 41 deletions
|
@ -213,6 +213,9 @@ our $RULE_KINDS = {
|
|||
recall_shelf_time => {
|
||||
scope => [ 'branchcode', 'categorycode', 'itemtype' ],
|
||||
},
|
||||
holds_pickup_period => {
|
||||
scope => [ 'branchcode', 'categorycode', 'itemtype' ],
|
||||
},
|
||||
# Not included (deprecated?):
|
||||
# * accountsent
|
||||
# * reservecharge
|
||||
|
|
11
Koha/Hold.pm
11
Koha/Hold.pm
|
@ -233,6 +233,17 @@ sub set_waiting {
|
|||
|
||||
my $new_expiration_date = dt_from_string($self->waitingdate)->clone->add( days => $max_pickup_delay );
|
||||
|
||||
my $rule = Koha::CirculationRules->get_effective_rule({
|
||||
categorycode => $self->borrower->categorycode,
|
||||
itemtype => $self->item->effective_itemtype,
|
||||
branchcode => $self->branchcode,
|
||||
rule_name => 'holds_pickup_period',
|
||||
});
|
||||
if ( defined($rule) and $rule->rule_value ne '' ){
|
||||
# circulation rule overrides ReservesMaxPickUpDelay
|
||||
$max_pickup_delay = $rule->rule_value;
|
||||
}
|
||||
|
||||
if ( C4::Context->preference("ExcludeHolidaysFromMaxPickUpDelay") ) {
|
||||
my $itemtype = $self->item ? $self->item->effective_itemtype : $self->biblio->itemtype;
|
||||
my $daysmode = Koha::CirculationRules->get_effective_daysmode(
|
||||
|
|
|
@ -298,47 +298,46 @@ elsif ($op eq 'add') {
|
|||
my $recall_due_date_interval = $input->param('recall_due_date_interval');
|
||||
my $recall_overdue_fine = $input->param('recall_overdue_fine');
|
||||
my $recall_shelf_time = $input->param('recall_shelf_time');
|
||||
my $holds_pickup_period = strip_non_numeric($input->param('holds_pickup_period'));
|
||||
|
||||
my $rules = {
|
||||
maxissueqty => $maxissueqty,
|
||||
maxonsiteissueqty => $maxonsiteissueqty,
|
||||
rentaldiscount => $rentaldiscount,
|
||||
fine => $fine,
|
||||
finedays => $finedays,
|
||||
maxsuspensiondays => $maxsuspensiondays,
|
||||
suspension_chargeperiod => $suspension_chargeperiod,
|
||||
firstremind => $firstremind,
|
||||
chargeperiod => $chargeperiod,
|
||||
chargeperiod_charge_at => $chargeperiod_charge_at,
|
||||
issuelength => $issuelength,
|
||||
daysmode => $daysmode,
|
||||
lengthunit => $lengthunit,
|
||||
hardduedate => $hardduedate,
|
||||
hardduedatecompare => $hardduedatecompare,
|
||||
renewalsallowed => $renewalsallowed,
|
||||
unseen_renewals_allowed => $unseen_renewals_allowed,
|
||||
renewalperiod => $renewalperiod,
|
||||
norenewalbefore => $norenewalbefore,
|
||||
noautorenewalbefore => $noautorenewalbefore,
|
||||
auto_renew => $auto_renew,
|
||||
no_auto_renewal_after => $no_auto_renewal_after,
|
||||
no_auto_renewal_after_hard_limit => $no_auto_renewal_after_hard_limit,
|
||||
reservesallowed => $reservesallowed,
|
||||
holds_per_record => $holds_per_record,
|
||||
holds_per_day => $holds_per_day,
|
||||
onshelfholds => $onshelfholds,
|
||||
opacitemholds => $opacitemholds,
|
||||
overduefinescap => $overduefinescap,
|
||||
cap_fine_to_replacement_price => $cap_fine_to_replacement_price,
|
||||
article_requests => $article_requests,
|
||||
note => $note,
|
||||
decreaseloanholds => $decreaseloanholds,
|
||||
recalls_allowed => $recalls_allowed,
|
||||
recalls_per_record => $recalls_per_record,
|
||||
on_shelf_recalls => $on_shelf_recalls,
|
||||
recall_due_date_interval => $recall_due_date_interval,
|
||||
recall_overdue_fine => $recall_overdue_fine,
|
||||
recall_shelf_time => $recall_shelf_time,
|
||||
maxissueqty => $maxissueqty,
|
||||
maxonsiteissueqty => $maxonsiteissueqty,
|
||||
rentaldiscount => $rentaldiscount,
|
||||
fine => $fine,
|
||||
finedays => $finedays,
|
||||
maxsuspensiondays => $maxsuspensiondays,
|
||||
suspension_chargeperiod => $suspension_chargeperiod,
|
||||
firstremind => $firstremind,
|
||||
chargeperiod => $chargeperiod,
|
||||
chargeperiod_charge_at => $chargeperiod_charge_at,
|
||||
issuelength => $issuelength,
|
||||
daysmode => $daysmode,
|
||||
lengthunit => $lengthunit,
|
||||
hardduedate => $hardduedate,
|
||||
hardduedatecompare => $hardduedatecompare,
|
||||
renewalsallowed => $renewalsallowed,
|
||||
unseen_renewals_allowed => $unseen_renewals_allowed,
|
||||
renewalperiod => $renewalperiod,
|
||||
norenewalbefore => $norenewalbefore,
|
||||
noautorenewalbefore => $noautorenewalbefore,
|
||||
auto_renew => $auto_renew,
|
||||
no_auto_renewal_after => $no_auto_renewal_after,
|
||||
no_auto_renewal_after_hard_limit => $no_auto_renewal_after_hard_limit,
|
||||
onshelfholds => $onshelfholds,
|
||||
opacitemholds => $opacitemholds,
|
||||
overduefinescap => $overduefinescap,
|
||||
cap_fine_to_replacement_price => $cap_fine_to_replacement_price,
|
||||
article_requests => $article_requests,
|
||||
note => $note,
|
||||
decreaseloanholds => $decreaseloanholds,
|
||||
recalls_allowed => $recalls_allowed,
|
||||
recalls_per_record => $recalls_per_record,
|
||||
on_shelf_recalls => $on_shelf_recalls,
|
||||
recall_due_date_interval => $recall_due_date_interval,
|
||||
recall_overdue_fine => $recall_overdue_fine,
|
||||
recall_shelf_time => $recall_shelf_time,
|
||||
holds_pickup_period => $holds_pickup_period,
|
||||
};
|
||||
|
||||
Koha::CirculationRules->set_rules(
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
$DBversion = 'XXX';
|
||||
if( CheckVersion( $DBversion ) ) {
|
||||
$dbh->do(q{INSERT IGNORE INTO circulation_rules (branchcode, categorycode, itemtype, rule_name, rule_value) VALUES (NULL, NULL, NULL, 'holds_pickup_period', NULL) });
|
||||
|
||||
NewVersion( $DBversion, 8367, "Add holds_pickup_period circulation rule" );
|
||||
}
|
|
@ -287,6 +287,7 @@ if ( $step == 5 ) {
|
|||
recall_due_date_interval => undef,
|
||||
recall_overdue_fine => undef,
|
||||
recall_shelf_time => undef,
|
||||
holds_pickup_period => undef,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@
|
|||
<th>Holds per record (count)</th>
|
||||
<th>On shelf holds allowed</th>
|
||||
<th>OPAC item level holds</th>
|
||||
<th>Holds pickup period (day)</th>
|
||||
[% IF Koha.Preference('ArticleRequests') %]
|
||||
<th>Article requests</th>
|
||||
[% END %]
|
||||
|
@ -206,8 +207,9 @@
|
|||
[% SET recall_due_date_interval = all_rules.$c.$i.recall_due_date_interval %]
|
||||
[% SET recall_overdue_fine = all_rules.$c.$i.recall_overdue_fine %]
|
||||
[% SET recall_shelf_time = all_rules.$c.$i.recall_shelf_time %]
|
||||
[% SET holds_pickup_period = all_rules.$c.$i.holds_pickup_period %]
|
||||
|
||||
[% SET show_rule = note || maxissueqty || maxonsiteissueqty || issuelength || daysmode || lengthunit || hardduedate || hardduedatecompare || fine || chargeperiod || chargeperiod_charge_at || firstremind || overduefinescap || cap_fine_to_replacement_price || finedays || maxsuspensiondays || suspension_chargeperiod || renewalsallowed || unseenrenewalsallowed || renewalperiod || norenewalbefore || noautorenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed || holds_per_day || holds_per_record || onshelfholds || opacitemholds || article_requests || rentaldiscount || decreaseloanholds || recalls_allowed || recalls_per_record || on_shelf_recalls || recall_due_date_interval || recall_overdue_fine || recall_shelf_time %]
|
||||
[% SET show_rule = note || maxissueqty || maxonsiteissueqty || issuelength || daysmode || lengthunit || hardduedate || hardduedatecompare || fine || chargeperiod || chargeperiod_charge_at || firstremind || overduefinescap || cap_fine_to_replacement_price || finedays || maxsuspensiondays || suspension_chargeperiod || renewalsallowed || unseenrenewalsallowed || renewalperiod || norenewalbefore || noautorenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed || holds_per_day || holds_per_record || onshelfholds || opacitemholds || article_requests || rentaldiscount || decreaseloanholds || recalls_allowed || recalls_per_record || on_shelf_recalls || recall_due_date_interval || recall_overdue_fine || recall_shelf_time || holds_pickup_period %]
|
||||
[% IF show_rule %]
|
||||
[% SET row_count = row_count + 1 %]
|
||||
<tr row_countd="row_[% row_count | html %]">
|
||||
|
@ -370,6 +372,7 @@
|
|||
<span>Don't allow</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td>[% holds_pickup_period | html %]</td>
|
||||
[% IF Koha.Preference('ArticleRequests') %]
|
||||
<td data-code="[% article_requests | html %]">
|
||||
[% IF article_requests == 'no' %]
|
||||
|
@ -519,6 +522,7 @@
|
|||
<option value="F">Force</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" name="holds_pickup_period" id="holds_pickup_period" size="2" /></td>
|
||||
[% IF Koha.Preference('ArticleRequests') %]
|
||||
<td>
|
||||
<select id="article_requests" name="article_requests">
|
||||
|
@ -589,6 +593,7 @@
|
|||
<th>Holds per record (count)</th>
|
||||
<th>On shelf holds allowed</th>
|
||||
<th>OPAC item level holds</th>
|
||||
<th>Holds pickup period (day)</th>
|
||||
[% IF Koha.Preference('ArticleRequests') %]
|
||||
<th>Article requests</th>
|
||||
[% END %]
|
||||
|
|
|
@ -283,6 +283,10 @@
|
|||
[% END # / UNLESS singleBranchMode %]
|
||||
</ul>
|
||||
|
||||
[% IF pickup_delays %]
|
||||
<p id="pickup_delay" style="display:none;">When your item is ready for pickup, you will have <span id="pickup_delay_days"></span> days to pick it up from this library.</p>
|
||||
[% END %]
|
||||
|
||||
<a class="toggle-hold-options" id="toggle-hold-options-[% bibitemloo.biblionumber | html %]" style="display:none;" href="#">Show more options</a>
|
||||
|
||||
<div id="hold-options-[% bibitemloo.biblionumber | html %]" class="hold-options">
|
||||
|
@ -506,6 +510,16 @@
|
|||
var MSG_EMPTY_START_DATE = _("Hold start date should be filled.");
|
||||
var MSG_EMPTY_END_DATE = _("Hold expiration date should be filled.");
|
||||
|
||||
function calculate_delay_days(){
|
||||
var selected_branch = $("#branch_1").val();
|
||||
[% FOREACH branchcode IN pickup_delays.keys %]
|
||||
var branchcode = "[% branchcode | html %]";
|
||||
if ( branchcode == selected_branch ) {
|
||||
$("#pickup_delay_days").text([% pickup_delays.$branchcode | html %]);
|
||||
}
|
||||
[% END %]
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$(".toggle_unholdable").click(function(e){
|
||||
|
@ -513,6 +527,12 @@
|
|||
$(this).parent('div').find(".unholdable").toggle();
|
||||
});
|
||||
|
||||
calculate_delay_days();
|
||||
$("#pickup_delay").show();
|
||||
$("#branch_1").change(function(){
|
||||
calculate_delay_days();
|
||||
});
|
||||
|
||||
$("#hold-request-form").preventDoubleFormSubmit();
|
||||
var copiesRowId = null;
|
||||
var wasSpecific = false;
|
||||
|
|
|
@ -339,6 +339,17 @@ sub GetWaitingHolds {
|
|||
|
||||
my $waiting_date = dt_from_string( $issue->{waitingdate}, 'sql' );
|
||||
|
||||
my $rule = Koha::CirculationRules->get_effective_rule({
|
||||
categorycode => $issue->{categorycode},
|
||||
itemtype => $item->effective_itemtype,
|
||||
branchcode => $issue->{branchcode},
|
||||
rule_name => 'holds_pickup_period',
|
||||
});
|
||||
if ( defined($rule) and $rule->rule_value ne '' ){
|
||||
# circulation rule overrides ReservesMaxPickUpDelay
|
||||
$pickupdelay = $rule->rule_value;
|
||||
}
|
||||
|
||||
$issue->{'date_due'} = output_pref({dt => dt_from_string($issue->{expirationdate}), dateformat => 'iso' });
|
||||
$issue->{'level'} = 1; # only one level for Hold Waiting notifications
|
||||
|
||||
|
|
|
@ -626,4 +626,19 @@ if (
|
|||
);
|
||||
}
|
||||
|
||||
my @branches = Koha::Libraries->search();
|
||||
my %hold_pickup_delay_by_branch = ();
|
||||
|
||||
foreach my $branch ( @branches ) {
|
||||
my $rule = Koha::CirculationRules->get_effective_rule({
|
||||
categorycode => $patron->categorycode,
|
||||
branchcode => $branch->branchcode,
|
||||
itemtype => undef,
|
||||
rule_name => 'holds_pickup_period',
|
||||
});
|
||||
$hold_pickup_delay_by_branch{$branch->branchcode} = $rule->rule_value if ( $rule and $rule->rule_value );
|
||||
}
|
||||
|
||||
$template->param( pickup_delays => \%hold_pickup_delay_by_branch );
|
||||
|
||||
output_html_with_http_headers $query, $cookie, $template->output, undef, { force_no_caching => 1 };
|
||||
|
|
|
@ -8,7 +8,7 @@ use Koha::DateUtils qw( dt_from_string );
|
|||
use t::lib::Mocks;
|
||||
use t::lib::TestBuilder;
|
||||
|
||||
use Test::More tests => 11;
|
||||
use Test::More tests => 13;
|
||||
|
||||
use_ok('C4::Reserves', qw( ModReserve ModReserveAffect ));
|
||||
|
||||
|
@ -63,11 +63,24 @@ my $biblio = $builder->build_sample_biblio;
|
|||
my $biblio2 = $builder->build_sample_biblio;
|
||||
my $biblio3 = $builder->build_sample_biblio;
|
||||
my $biblio4 = $builder->build_sample_biblio;
|
||||
my $biblio5 = $builder->build_sample_biblio;
|
||||
my $biblio6 = $builder->build_sample_biblio;
|
||||
|
||||
my $item1 = $builder->build_sample_item({biblionumber => $biblio->biblionumber});
|
||||
my $item2 = $builder->build_sample_item({biblionumber => $biblio2->biblionumber});
|
||||
my $item3 = $builder->build_sample_item({biblionumber => $biblio3->biblionumber});
|
||||
my $item4 = $builder->build_sample_item({biblionumber => $biblio4->biblionumber});
|
||||
my $item5 = $builder->build_sample_item({biblionumber => $biblio5->biblionumber});
|
||||
my $item6 = $builder->build_sample_item({biblionumber => $biblio6->biblionumber});
|
||||
|
||||
Koha::CirculationRules->set_rules({
|
||||
categorycode => undef,
|
||||
itemtype => undef,
|
||||
branchcode => undef,
|
||||
rules => {
|
||||
holds_pickup_period => undef,
|
||||
}
|
||||
});
|
||||
|
||||
my $today = dt_from_string();
|
||||
|
||||
|
@ -199,4 +212,57 @@ ModReserveAffect( $item4->itemnumber, $patron2->{borrowernumber}, 0, $reserve4->
|
|||
my $r4 = Koha::Holds->find($reserve4->{reserve_id});
|
||||
is($r4->expirationdate, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
|
||||
|
||||
Koha::CirculationRules->set_rules({
|
||||
categorycode => $patron1->{categorycode},
|
||||
itemtype => undef,
|
||||
branchcode => undef,
|
||||
rules => {
|
||||
holds_pickup_period => '3',
|
||||
}
|
||||
});
|
||||
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 7);
|
||||
|
||||
my $reserve5_reservedate = $today->clone;
|
||||
my $reserve5_expirationdate = $reserve5_reservedate->add(days => 3);
|
||||
|
||||
my $reserve5 = $builder->build({
|
||||
source => 'Reserve',
|
||||
value => {
|
||||
borrowernumber => $patron1->{borrowernumber},
|
||||
reservedate => $reserve5_reservedate->ymd,
|
||||
expirationdate => undef,
|
||||
biblionumber => $biblio5->biblionumber,
|
||||
branchcode => 'LIB2',
|
||||
priority => 1,
|
||||
found => '',
|
||||
},
|
||||
});
|
||||
|
||||
ModReserveAffect( $item5->itemnumber, $patron1->{borrowernumber});
|
||||
my $r5 = Koha::Holds->find($reserve5->{reserve_id});
|
||||
|
||||
is($r5->expirationdate, $reserve5_expirationdate->ymd, 'Expiration date should be set to today + 3 based on circulation rules' );
|
||||
|
||||
my $reserve6_reservedate = $today->clone;
|
||||
# add 3 days of pickup + 1 day of holiday
|
||||
my $reserve6_expirationdate = $reserve6_reservedate->add(days => 5);
|
||||
|
||||
my $reserve6 = $builder->build({
|
||||
source => 'Reserve',
|
||||
value => {
|
||||
borrowernumber => $patron1->{borrowernumber},
|
||||
reservedate => $reserve6_reservedate->ymd,
|
||||
expirationdate => undef,
|
||||
biblionumber => $biblio6->biblionumber,
|
||||
branchcode => 'LIB1',
|
||||
priority => 1,
|
||||
found => '',
|
||||
},
|
||||
});
|
||||
|
||||
ModReserveAffect( $item6->itemnumber, $patron1->{borrowernumber});
|
||||
my $r6 = Koha::Holds->find($reserve6->{reserve_id});
|
||||
|
||||
is($r6->expirationdate, $reserve6_expirationdate->ymd, 'Expiration date should be set to today + 4 based on circulation rules and including a holiday' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
|
|
Loading…
Reference in a new issue