From 60022397477ab4478cdca953c14a3c2dbb650ce2 Mon Sep 17 00:00:00 2001 From: Aleisha Amohia Date: Wed, 20 Oct 2021 15:47:47 +1300 Subject: [PATCH] Bug 24718: Hour based holds on staff client Tests in t/db_dependent/Holds.t --- C4/HoldsQueue.pm | 4 +- C4/Reserves.pm | 31 +++++++- Koha/Item.pm | 2 +- .../prog/en/includes/holds_table.inc | 10 ++- .../prog/en/includes/waiting_holds.inc | 6 +- .../prog/en/modules/circ/pendingreserves.tt | 6 +- .../prog/en/modules/circ/view_holdsqueue.tt | 8 +- .../prog/en/modules/members/holdshistory.tt | 11 ++- .../prog/en/modules/reserve/request.tt | 25 ++++++- svc/holds | 25 +++++-- t/db_dependent/Holds.t | 75 ++++++++++++++++++- 11 files changed, 174 insertions(+), 29 deletions(-) diff --git a/C4/HoldsQueue.pm b/C4/HoldsQueue.pm index 8255fdbd137..538428f706c 100644 --- a/C4/HoldsQueue.pm +++ b/C4/HoldsQueue.pm @@ -240,7 +240,7 @@ sub GetBibsWithPendingHoldRequests { FROM reserves WHERE found IS NULL AND priority > 0 - AND reservedate <= CURRENT_DATE() + AND reservedate <= CURRENT_TIMESTAMP() AND suspend = 0 "; my $sth = $dbh->prepare($bib_query); @@ -284,7 +284,7 @@ sub GetPendingHoldRequestsForBib { WHERE biblionumber = ? AND found IS NULL AND priority > 0 - AND reservedate <= CURRENT_DATE() + AND reservedate <= CURRENT_TIMESTAMP() AND suspend = 0 ORDER BY priority"; my $sth = $dbh->prepare($request_query); diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 987543e1cde..8c2e7a90a78 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -195,7 +195,26 @@ sub AddReserve { my $non_priority = $params->{non_priority}; my $item_group_id = $params->{item_group_id}; - $resdate ||= dt_from_string; + if ( C4::Context->preference('HourBasedHolds') ){ + if ( $resdate ){ + $resdate = dt_from_string( $resdate ); + } else { + $resdate = dt_from_string(); + } + if ( $expdate ){ + $expdate = dt_from_string( $expdate ); + } + } else { + # add hour and minute components + if ( $resdate ){ + $resdate = dt_from_string( $resdate )->set({ hour => 00, minute => 00, second => 00 }); + } else { + $resdate = dt_from_string(); + } + if ( $expdate ){ + $expdate = dt_from_string( $expdate )->set({ hour => 23, minute => 59, second => 59 }); + } + } # if we have an item selectionned, and the pickup branch is the same as the holdingbranch # of the document, we force the value $priority and $found . @@ -520,11 +539,15 @@ sub CanItemBeReserved { } } + my $dtf = Koha::Database->new->schema->storage->datetime_parser; + my $fromdate = dt_from_string->set({ hour => 00, minute => 00, second => 00 }); + my $todate = dt_from_string->set({ hour => 23, minute => 59, second => 59 }); + if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '') { my $today_holds = Koha::Holds->search({ borrowernumber => $patron->borrowernumber, - reservedate => dt_from_string->date + reservedate => [ -and => { '>=' => $dtf->format_datetime($fromdate) }, { '<=' => $dtf->format_datetime($todate) } ], }); return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day; } @@ -1005,7 +1028,7 @@ sub CancelExpiredReserves { my $dtf = Koha::Database->new->schema->storage->datetime_parser; my $params = { -or => [ - { expirationdate => { '<', $dtf->format_date($today) } }, + { expirationdate => { '<', $dtf->format_datetime($today) } }, { patron_expiration_date => { '<' => $dtf->format_date($today) } } ] }; @@ -2300,7 +2323,7 @@ sub CalculatePriority { $sql.= ' AND ( reservedate <= ? )'; } else { - $sql.= ' AND ( reservedate < NOW() )'; + $sql.= ' AND ( reservedate <= NOW() )'; } my $dbh = C4::Context->dbh(); my @row = $dbh->selectrow_array( diff --git a/Koha/Item.pm b/Koha/Item.pm index b9c591b9735..b2283ea772d 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -853,7 +853,7 @@ sub current_holds { itemnumber => $self->itemnumber, suspend => 0, -or => [ - reservedate => { '<=' => $dtf->format_date(dt_from_string) }, + reservedate => { '<=' => $dtf->format_datetime(dt_from_string) }, waitingdate => { '!=' => undef }, ], }; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc index d5b9a67a4f8..4c2458d5d14 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc @@ -119,13 +119,17 @@ [% hold.notes | html | html_line_break %] [% IF Koha.Preference('AllowHoldDateInFuture') %] - + [% ELSE %] - [% hold.date | $KohaDates %] + [% IF Koha.Preference('HourBasedHolds') %] + [% hold.date | $KohaDates with_hours = 1 %] + [% ELSE %] + [% hold.date | $KohaDates %] + [% END %] [% END %] - + [%- IF ( hold.found ) -%] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc index e6caa50f4a0..87e4e59d80a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc @@ -27,7 +27,11 @@ [% reserveloo.waitingdate | $KohaDates %] - [% reserveloo.reservedate | $KohaDates %] + [% IF Koha.Preference('HourBasedHolds') %] + [% reserveloo.reservedate | $KohaDates with_hours = 1 %] + [% ELSE %] + [% reserveloo.reservedate | $KohaDates %] + [% END %] [% IF table_name == 'holdscr' %] [% IF reserveloo.cancellation_requests.count %] [% FOREACH cancellation_request IN reserveloo.cancellation_requests %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt index 5d44bf09e77..8c39ad813a9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt @@ -200,7 +200,11 @@ - [% hold.reservedate | $KohaDates %] in [% Branches.GetName ( hold.branchcode ) | html %] + [% IF Koha.Preference('HourBasedHolds') %] + [% hold.reservedate | $KohaDates with_hours = 1 %] in [% Branches.GetName ( hold.branchcode ) | html %] + [% ELSE %] + [% hold.reservedate | $KohaDates %] in [% Branches.GetName ( hold.branchcode ) | html %] + [% END %] [% hold.reservenotes | html %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt index 27e2a95501e..eaeb1f57708 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt @@ -214,7 +214,13 @@ [% itemsloo.patron.category.description | html %] ([% itemsloo.patron.categorycode | html %]) [% Branches.GetName( itemsloo.pickbranch ) | html %] - [% itemsloo.reservedate | $KohaDates %] + + [% IF Koha.Preference('HourBasedHolds') %] + [% itemsloo.reservedate | $KohaDates with_hours = 1 %] + [% ELSE %] + [% itemsloo.reservedate | $KohaDates %] + [% END %] + [% itemsloo.notes | html %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt index ce521036d17..f7ffd5e5ce6 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt @@ -78,10 +78,13 @@ [% hold.biblio.author | html %] [% hold.item.barcode | html %] [% Branches.GetName( hold.branchcode ) | html %] - [% hold.reservedate | $KohaDates %] - - [% hold.expirationdate | $KohaDates %] - + [% IF Koha.Preference('HourBasedHolds') %] + [% hold.reservedate | $KohaDates with_hours = 1 %] + [% hold.expirationdate | $KohaDates with_hours = 1 %] + [% ELSE %] + [% hold.reservedate | $KohaDates %] + [% hold.expirationdate | $KohaDates %] + [% END %] [% hold.waitingdate | $KohaDates %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt index e2d33c5415b..4eb6381d64a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -587,13 +587,13 @@ [% IF ( Koha.Preference('AllowHoldDateInFuture') ) %]
  • - +
  • [% END %]
  • - +
  • [% UNLESS ( multi_hold ) %] @@ -1385,6 +1385,27 @@ }); [% END %] + var startPicker = $("#reserve_date").flatpickr({ + [% IF Koha.Preference('HourBasedHolds') %] + enableTime: true, + dateFormat: flatpickr_dateformat_string + " " + flatpickr_timeformat_string, + [% END %] + }); + + var endPicker = $("#expiration_date").flatpickr({ + [% IF Koha.Preference('HourBasedHolds') %] + enableTime: true, + dateFormat: flatpickr_dateformat_string + " " + flatpickr_timeformat_string, + [% END %] + }); + + [% IF Koha.Preference('HourBasedHolds') %] + $(".holdst_reservedate, .futuredate").flatpickr({ + enableTime: true, + dateFormat: flatpickr_dateformat_string + " " + flatpickr_timeformat_string, + }); + [% END %] + var my_table = $("#requestspecific").dataTable($.extend(true, {}, dataTablesDefaults, { 'bPaginate': false, "sDom": '<"top pager"ilf>t', diff --git a/svc/holds b/svc/holds index 8043297573a..9518b119361 100755 --- a/svc/holds +++ b/svc/holds @@ -114,19 +114,32 @@ while ( my $h = $holds_rs->next() ) { waiting_here => $h->branch()->branchcode() eq $branch, priority => $h->priority(), itemtype_limit => $itemtype_limit, - reservedate_formatted => $h->reservedate() ? output_pref( - { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } - ) - : q{}, suspend_until_formatted => $h->suspend_until() ? output_pref( { dt => dt_from_string( $h->suspend_until() ), dateonly => 1 } ) : q{}, - expirationdate_formatted => $h->expirationdate() ? output_pref( + }; + + if ( C4::Context->preference('HourBasedHolds') ){ + $hold->{reservedate_formatted} = $h->reservedate() ? output_pref( + { dt => dt_from_string( $h->reservedate() ) } + ) + : q{}, + $hold->{expirationdate_formatted} = $h->expirationdate() ? output_pref( + { dt => dt_from_string( $h->expirationdate() ) } + ) + : q{}, + } else { + $hold->{reservedate_formatted} = $h->reservedate() ? output_pref( + { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } + ) + : q{}, + $hold->{expirationdate_formatted} = $h->expirationdate() ? output_pref( { dt => dt_from_string( $h->expirationdate() ), dateonly => 1 } ) : q{}, - }; + } + $hold->{transfered} = 0; $hold->{not_transfered} = 0; diff --git a/t/db_dependent/Holds.t b/t/db_dependent/Holds.t index 29e773e3990..ed43e06cadd 100755 --- a/t/db_dependent/Holds.t +++ b/t/db_dependent/Holds.t @@ -7,7 +7,7 @@ use t::lib::TestBuilder; use C4::Context; -use Test::More tests => 76; +use Test::More tests => 77; use Test::Exception; use MARC::Record; @@ -108,7 +108,7 @@ my $reservedate = $first_hold->reservedate; my $borrowernumber = $first_hold->borrowernumber; my $branch_1code = $first_hold->branchcode; my $reserve_id = $first_hold->reserve_id; -is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date"); +is( dt_from_string($reservedate), dt_from_string, "holds_placed_today should return a valid reserve date"); is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber"); is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode"); ok($reserve_id, "Test holds_placed_today()"); @@ -942,7 +942,7 @@ subtest 'CanItemBeReserved / holds_per_day tests' => sub { is_deeply( CanItemBeReserved( $patron, $item_2 ), { status => 'tooManyReservesToday', limit => 2 }, - 'Patron cannot a third item with 2 reserves daily cap' + 'Patron cannot reserve a third item with 2 reserves daily cap' ); # Update last hold so reservedate is in the past, so 2 holds, but different day @@ -1705,7 +1705,7 @@ subtest 'ModReserve can only update expirationdate for found holds' => sub { $hold = Koha::Holds->find($reserve_id); - is( $hold->expirationdate, '1981-06-10', + is( dt_from_string( $hold->expirationdate )->ymd, '1981-06-10', 'Found hold expiration date updated correctly' ); is( $hold->priority, '0', 'Found hold priority was not updated' ); @@ -1807,3 +1807,70 @@ subtest 'Koha::Holds->get_items_that_can_fill returns items with datecancelled o $schema->storage->txn_rollback; }; + +subtest 'HourBasedHolds' => sub { + plan tests => 4; + $schema->storage->txn_begin; + + my $category = $builder->build({ source => 'Category' }); + my $branch = $builder->build({ source => 'Branch' })->{ branchcode }; + my $biblio = $builder->build_sample_biblio( { itemtype => 'DUMMY' } ); + my $itemnumber = $builder->build_sample_item( + { library => $branch, biblionumber => $biblio->biblionumber } ) + ->itemnumber; + + my $borrowernumber = Koha::Patron->new( + { + firstname => 'firstname', + surname => 'surname', + categorycode => $category->{categorycode}, + branchcode => $branch, + } + )->store->borrowernumber; + + t::lib::Mocks::mock_preference('HourBasedHolds', 1); + + my $reservation_date = DateTime->now->set( hour => 7, minute => 30 ); + my $expiration_date = DateTime->now->set( hour => 19, minute => 30 ); + + my $reserve_id = AddReserve( + { + branchcode => $branch, + borrowernumber => $borrowernumber, + biblionumber => $biblio->biblionumber, + priority => + C4::Reserves::CalculatePriority( $biblio->biblionumber ), + itemnumber => $itemnumber, + reservation_date => $reservation_date, + expiration_date => $expiration_date, + } + ); + + my $hold = Koha::Holds->find($reserve_id); + is( dt_from_string( $hold->reservedate )->hour, 07, "Hold reserve date is set correctly with hours when HourBasedHolds enabled" ); + is( dt_from_string( $hold->expirationdate )->hour, 19, "Hold expiration date is set correctly with hours when HourBasedHolds enabled" ); + + t::lib::Mocks::mock_preference('HourBasedHolds', 0); + + $reservation_date = DateTime->now->ymd; + $expiration_date = DateTime->now->ymd; + + $reserve_id = AddReserve( + { + branchcode => $branch, + borrowernumber => $borrowernumber, + biblionumber => $biblio->biblionumber, + priority => + C4::Reserves::CalculatePriority( $biblio->biblionumber ), + itemnumber => $itemnumber, + reservation_date => $reservation_date, + expiration_date => $expiration_date, + } + ); + + $hold = Koha::Holds->find($reserve_id); + is( dt_from_string( $hold->reservedate )->hour, 00, "Hold reserve date is set correctly when HourBasedHolds disabled" ); + is( dt_from_string( $hold->expirationdate )->hour, 23, "Hold expiration date is set correctly when HourBasedHolds disabled" ); + + $schema->storage->txn_rollback; +}; -- 2.20.1