From 1896d6b1be203308fcde072b702ba96a7463aa20 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 10 May 2022 09:04:36 +0200 Subject: [PATCH] Bug 30650: Allow to restrict curbside pickup for waiting holds only Sponsored-by: Association KohaLa - https://koha-fr.org/ Signed-off-by: Koha Team University Lyon 3 --- Koha/CurbsidePickup.pm | 16 ++++- Koha/CurbsidePickupPolicy.pm | 16 +++++ Koha/Exceptions/CurbsidePickup.pm | 4 ++ admin/curbside_pickup.pl | 1 + .../prog/en/modules/admin/curbside_pickup.tt | 10 +++ .../prog/en/modules/circ/curbside_pickups.tt | 42 +++++++------ .../en/modules/opac-curbside-pickups.tt | 15 +++++ t/db_dependent/Koha/CurbsidePickups.t | 61 ++++++++----------- 8 files changed, 107 insertions(+), 58 deletions(-) diff --git a/Koha/CurbsidePickup.pm b/Koha/CurbsidePickup.pm index 7fd0cac65b9..8cf4e89d3f4 100644 --- a/Koha/CurbsidePickup.pm +++ b/Koha/CurbsidePickup.pm @@ -49,6 +49,20 @@ Koha::CurbsidePickup - Koha Curbside Pickup Object class sub new { my ( $self, $params ) = @_; + my $policy = + Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } ); + + Koha::Exceptions::CurbsidePickup::NotEnabled->throw + unless $policy && $policy->enabled; + + if ( $policy->enable_waiting_holds_only ) { + my $patron = Koha::Patrons->find( $params->{borrowernumber} ); + my $waiting_holds = $patron->holds->search( + { found => 'W', branchcode => $params->{branchcode} } ); + + Koha::Exceptions::CurbsidePickup::NoWaitingHolds->throw + unless $waiting_holds->count; + } my $existing_curbside_pickups = Koha::CurbsidePickups->search( { branchcode => $params->{branchcode}, @@ -62,8 +76,6 @@ sub new { borrowernumber => $params->{borrowernumber} ) if $existing_curbside_pickups->count; - my $policy = - Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } ); my $is_valid = $policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} ); unless ($is_valid) { diff --git a/Koha/CurbsidePickupPolicy.pm b/Koha/CurbsidePickupPolicy.pm index 118e178f498..07e0719d170 100644 --- a/Koha/CurbsidePickupPolicy.pm +++ b/Koha/CurbsidePickupPolicy.pm @@ -47,6 +47,14 @@ sub library { return Koha::Library->_new_from_dbic( $rs ); } +=head3 opening_slots + +$policy->opening_slots + +Return the list of opening slots (Koha::CurbsidePickupOpeningSlots object) + +=cut + sub opening_slots { my ( $self ) = @_; my $rs = $self->_result->curbside_pickup_opening_slots; @@ -54,6 +62,14 @@ sub opening_slots { return Koha::CurbsidePickupOpeningSlots->_new_from_dbic( $rs ); } +=head3 add_opening_slot + +$policy->add("$d-12:00-15:00"); + +Add a new opening slot for this library. It must be formatted "day:start:end" with 'start' and 'end' in 24-hour format. + +=cut + sub add_opening_slot { my ( $self, $slot ) = @_; diff --git a/Koha/Exceptions/CurbsidePickup.pm b/Koha/Exceptions/CurbsidePickup.pm index 1f25830b496..5fa7d01cba6 100644 --- a/Koha/Exceptions/CurbsidePickup.pm +++ b/Koha/Exceptions/CurbsidePickup.pm @@ -41,6 +41,10 @@ use Exception::Class ( isa => 'Koha::Exceptions::CurbsidePickup', description => 'No more pickups available for this slot', }, + 'Koha::Exceptions::CurbsidePickup::NoWaitingHolds' => { + isa => 'Koha::Exceptions::CurbsidePickup', + description => 'Cannot create a pickup, patron does not have waiting holds', + }, ); 1; diff --git a/admin/curbside_pickup.pl b/admin/curbside_pickup.pl index 21992c00f7d..528d8466116 100755 --- a/admin/curbside_pickup.pl +++ b/admin/curbside_pickup.pl @@ -45,6 +45,7 @@ if ( $op eq 'save' ) { my $params = { branchcode => $branchcode, enabled => scalar $input->param("enable-$branchcode") || 0, + enable_waiting_holds_only => scalar $input->param("enable-waiting-holds-only-$branchcode") || 0, pickup_interval => scalar $input->param("interval-$branchcode"), patrons_per_interval => scalar $input->param("max-per-interval-$branchcode"), patron_scheduled_pickup => scalar $input->param("patron-scheduled-$branchcode") || 0, diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/curbside_pickup.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/curbside_pickup.tt index e4594a1ad23..92afcd3f9e5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/curbside_pickup.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/curbside_pickup.tt @@ -112,6 +112,16 @@ [% END %] Enable patrons to schedule their own curbside pickups. + +
  • + + [% IF policies.$branchcode.enable_waiting_holds_only %] + + [% ELSE %] + + [% END %] + Enable only if the patron has waiting holds. +
  • diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/curbside_pickups.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/curbside_pickups.tt index f5a95163bf5..71549834281 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/curbside_pickups.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/curbside_pickups.tt @@ -433,23 +433,24 @@ [% ELSE %] -
    -
    - - - -
      -
    1. - - [% INCLUDE 'patron-title.inc' patron=patron %] -
    2. - -
    3. - - - [% SET waiting_holds = patron.holds.search( found => 'W', branchcode => logged_in_user.branchcode ) %] - [% IF waiting_holds.count %] - [% FOREACH h IN waiting_holds %] + [% SET waiting_holds = patron.holds.search( found => 'W', branchcode => logged_in_user.branchcode ) %] + [% IF !policy.enable_waiting_holds_only || waiting_holds.count > 0 %] + +
      + + + +
        +
      1. + + [% INCLUDE 'patron-title.inc' patron=patron %] +
      2. + +
      3. + + + [% IF waiting_holds.count %] + [% FOREACH h IN waiting_holds %]

        [% h.biblio.title | html %] ([% h.biblio.author | html %], [% h.item.barcode | html %])

        @@ -477,15 +478,16 @@
        - + [% ELSE %] +
        The patron does not have waitings holds.
        [% END %] - + [% END %] - + [% MACRO jsinclude BLOCK %] [% Asset.js("lib/dayjs/dayjs.min.js") | $raw %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-curbside-pickups.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-curbside-pickups.tt index 68a29987f6b..1462cfd7266 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-curbside-pickups.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-curbside-pickups.tt @@ -200,6 +200,7 @@ map[e.branchcode] = e; return map; }, {}); + let can_schedule_at = {}; [% FOR p IN policies %] var opening_slots = [% To.json(p.opening_slots.unblessed) | $raw %]; var slots_per_day = {}; @@ -209,6 +210,13 @@ slots_per_day[day].push(slot); }); policies['[% p.branchcode | html %]'].slots_per_day = slots_per_day; + + [% IF p.enable_waiting_holds_only %] + [% SET waiting_holds = logged_in_user.holds.search( found => 'W', branchcode => p.branchcode ) %] + [% UNLESS waiting_holds.count %] + policies['[% p.branchcode | html %]'].enabled = 0; + [% END %] + [% END %] [% END %] let existingPickupMoments = []; @@ -220,6 +228,13 @@ existingPickupMoments[pickup.branchcode].push(pickupMoment); }); + $("#pickup-branch option").each(function(){ + if ( $(this).val() != "" && !policies[$(this).val()].enabled ) { + $(this).prop("disabled", "disabled"); + $(this).attr("title", _("You don't have waiting holds at this location")); + } + }); + $('#pickup-branch').on('change', function() { let branchcode = $(this).val(); diff --git a/t/db_dependent/Koha/CurbsidePickups.t b/t/db_dependent/Koha/CurbsidePickups.t index 5e3fb36a0a9..6c0704ec5cb 100755 --- a/t/db_dependent/Koha/CurbsidePickups.t +++ b/t/db_dependent/Koha/CurbsidePickups.t @@ -54,6 +54,7 @@ my $policy = Koha::CurbsidePickupPolicy->new( { branchcode => $library->branchcode, enabled => 1, + enable_waiting_holds_only => 0, pickup_interval => 30, patrons_per_interval => 2, patron_scheduled_pickup => 1 @@ -63,6 +64,7 @@ my $policy_disabled = Koha::CurbsidePickupPolicy->new( { branchcode => $library_disabled->branchcode, enabled => 0, + enable_waiting_holds_only => 0, pickup_interval => 30, patrons_per_interval => 2, patron_scheduled_pickup => 1 @@ -75,32 +77,40 @@ $policy->add_opening_slot('1-12:00-18:00'); my $today = dt_from_string; subtest 'Create a pickup' => sub { - plan tests => 5; + plan tests => 7; # Day and datetime are ok my $next_monday = $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 ); my $schedule_dt = $next_monday->set_hour(15)->set_minute(00)->set_second(00); - my $cp = Koha::CurbsidePickup->new( + my $params = { branchcode => $library->branchcode, borrowernumber => $patron->borrowernumber, scheduled_pickup_datetime => $schedule_dt, notes => 'just a note' - } - )->store; + }; + + throws_ok { + Koha::CurbsidePickup->new({%$params, branchcode => $library_disabled->branchcode})->store; + } + 'Koha::Exceptions::CurbsidePickup::NotEnabled', + 'Cannot create pickup if the policy does not allow it'; + + $policy->enable_waiting_holds_only(1)->store; + throws_ok { + Koha::CurbsidePickup->new($params)->store; + } + 'Koha::Exceptions::CurbsidePickup::NoWaitingHolds', + 'Cannot create pickup for a patron without waiting hold if flag is set'; + + $policy->enable_waiting_holds_only(0)->store; + my $cp = Koha::CurbsidePickup->new($params)->store; is( $cp->status, 'to-be-staged' ); throws_ok { - Koha::CurbsidePickup->new( - { - branchcode => $library->branchcode, - borrowernumber => $patron->borrowernumber, - scheduled_pickup_datetime => $schedule_dt, - notes => 'just a note' - } - )->store + Koha::CurbsidePickup->new($params)->store } 'Koha::Exceptions::CurbsidePickup::TooManyPickups', 'Cannot create 2 pickups for the same patron'; @@ -112,14 +122,7 @@ subtest 'Create a pickup' => sub { $today->clone->add( days => ( 2 - $today->day_of_week ) % 7 ); $schedule_dt = $next_tuesday->set_hour(15)->set_minute(00)->set_second(00); throws_ok { - Koha::CurbsidePickup->new( - { - branchcode => $library->branchcode, - borrowernumber => $patron->borrowernumber, - scheduled_pickup_datetime => $schedule_dt, - notes => 'just a note' - } - )->store + Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store; } 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', 'Cannot create a pickup on a day without opening slots defined'; @@ -127,14 +130,7 @@ subtest 'Create a pickup' => sub { # Day ok but datetime not ok $schedule_dt = $next_monday->set_hour(19)->set_minute(00)->set_second(00); throws_ok { - Koha::CurbsidePickup->new( - { - branchcode => $library->branchcode, - borrowernumber => $patron->borrowernumber, - scheduled_pickup_datetime => $schedule_dt, - notes => 'just a note' - } - )->store + Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store; } 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', 'Cannot create a pickup on a time without opening slots defined'; @@ -142,14 +138,7 @@ subtest 'Create a pickup' => sub { # Day ok, datetime inside the opening slot, but wrong (15:15 for instance) $schedule_dt = $next_monday->set_hour(15)->set_minute(15)->set_second(00); throws_ok { - Koha::CurbsidePickup->new( - { - branchcode => $library->branchcode, - borrowernumber => $patron->borrowernumber, - scheduled_pickup_datetime => $schedule_dt, - notes => 'just a note' - } - )->store + Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store; } 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', 'Cannot create a pickup on a time that is not matching the start of an interval'; -- 2.25.1