From 9c35aa9d47adcf1f0109caa1f7483ae6ef81a7f7 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 | 21 ++++-- t/db_dependent/Holds.t | 75 ++++++++++++++++++- 11 files changed, 171 insertions(+), 28 deletions(-) diff --git a/C4/HoldsQueue.pm b/C4/HoldsQueue.pm index 5e555f4f959..22a91125fd6 100644 --- a/C4/HoldsQueue.pm +++ b/C4/HoldsQueue.pm @@ -224,7 +224,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); @@ -268,7 +268,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 c95a3d7ad42..771a6b476da 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -200,7 +200,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 . @@ -570,11 +589,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 _cache { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day; } @@ -1019,7 +1042,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) } } ] }; @@ -2271,7 +2294,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 22eaceac948..6ba8ae2ed4e 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -1055,7 +1055,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 27c080009e6..76b7d0512fd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc @@ -121,14 +121,18 @@ [% 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 %] [% UNLESS hold.expired %] - + [% ELSE %] [% hold.expirationdate | $KohaDates %] 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 484f1d609be..8ccd250923b 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 7eb29afe6b4..117300568c0 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt @@ -198,7 +198,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 24978b60d5a..cc980e62400 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 @@ -208,7 +208,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 33b00e5512e..281114f507f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt @@ -80,10 +80,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 025d5b0ca15..c94110c3e4a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -579,13 +579,13 @@ [% IF ( Koha.Preference('AllowHoldDateInFuture') ) %]
  • - +
  • [% END %]
  • - +
  • [% UNLESS ( multi_hold ) %] @@ -1384,6 +1384,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, { "paginate": false, "dom": '<"top pager"ilf>t', diff --git a/svc/holds b/svc/holds index dde088e16a9..3821a371799 100755 --- a/svc/holds +++ b/svc/holds @@ -115,16 +115,27 @@ while ( my $h = $holds_rs->next() ) { priority => $h->priority(), reservenotes => $h->reservenotes(), 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() + }; + + 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 4c78b4c480b..60331ac21a8 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 => 74; +use Test::More tests => 75; 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()"); @@ -939,7 +939,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 @@ -1702,7 +1702,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' ); @@ -1887,3 +1887,70 @@ subtest 'EmailPatronWhenHoldIsPlaced tests' => sub { $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.30.2