View | Details | Raw Unified | Return to bug 30650
Collapse All | Expand All

(-)a/Koha/CurbsidePickup.pm (-2 / +14 lines)
Lines 49-54 Koha::CurbsidePickup - Koha Curbside Pickup Object class Link Here
49
sub new {
49
sub new {
50
    my ( $self, $params ) = @_;
50
    my ( $self, $params ) = @_;
51
51
52
    my $policy =
53
      Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } );
54
55
    Koha::Exceptions::CubsidePickup::NotEnabled->throw
56
      unless $policy && $policy->enabled;
57
58
    if ( $policy->enable_waiting_holds_only ) {
59
        my $patron        = Koha::Patrons->find( $params->{borrowernumber} );
60
        my $waiting_holds = $patron->holds->search(
61
            { found => 'W', branchcode => $params->{branchcode} } );
62
63
        Koha::Exceptions::CubsidePickup::NoWaitingHolds->throw
64
          unless $waiting_holds->count;
65
    }
52
    my $existing_curbside_pickups = Koha::CurbsidePickups->search(
66
    my $existing_curbside_pickups = Koha::CurbsidePickups->search(
53
        {
67
        {
54
            branchcode                => $params->{branchcode},
68
            branchcode                => $params->{branchcode},
Lines 62-69 sub new { Link Here
62
        borrowernumber => $params->{borrowernumber}
76
        borrowernumber => $params->{borrowernumber}
63
    ) if $existing_curbside_pickups->count;
77
    ) if $existing_curbside_pickups->count;
64
78
65
    my $policy =
66
      Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } );
67
    my $is_valid =
79
    my $is_valid =
68
      $policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} );
80
      $policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} );
69
    unless ($is_valid) {
81
    unless ($is_valid) {
(-)a/Koha/CurbsidePickupPolicy.pm (+16 lines)
Lines 47-52 sub library { Link Here
47
    return Koha::Library->_new_from_dbic( $rs );
47
    return Koha::Library->_new_from_dbic( $rs );
48
}
48
}
49
49
50
=head3 opening_slots
51
52
$policy->opening_slots
53
54
Return the list of opening slots (Koha::CurbsidePickupOpeningSlots object)
55
56
=cut
57
50
sub opening_slots {
58
sub opening_slots {
51
    my ( $self ) = @_;
59
    my ( $self ) = @_;
52
    my $rs = $self->_result->curbside_pickup_opening_slots;
60
    my $rs = $self->_result->curbside_pickup_opening_slots;
Lines 54-59 sub opening_slots { Link Here
54
    return Koha::CurbsidePickupOpeningSlots->_new_from_dbic( $rs );
62
    return Koha::CurbsidePickupOpeningSlots->_new_from_dbic( $rs );
55
}
63
}
56
64
65
=head3 add_opening_slot
66
67
$policy->add("$d-12:00-15:00");
68
69
Add a new opening slot for this library. It must be formatted "day:start:end" with 'start' and 'end' in 24-hour format.
70
71
=cut
72
57
sub add_opening_slot {
73
sub add_opening_slot {
58
    my ( $self, $slot ) = @_;
74
    my ( $self, $slot ) = @_;
59
75
(-)a/Koha/Exceptions/CurbsidePickup.pm (+4 lines)
Lines 41-46 use Exception::Class ( Link Here
41
        isa         => 'Koha::Exceptions::CurbsidePickup',
41
        isa         => 'Koha::Exceptions::CurbsidePickup',
42
        description => 'No more pickups available for this slot',
42
        description => 'No more pickups available for this slot',
43
    },
43
    },
44
    'Koha::Exceptions::CubsidePickup::NoWaitingHolds' => {
45
        isa         => 'Koha::Exceptions::CurbsidePickup',
46
        description => 'Cannot create a pickup, patron does not have waiting holds',
47
    },
44
);
48
);
45
49
46
1;
50
1;
(-)a/admin/curbside_pickup.pl (+1 lines)
Lines 45-50 if ( $op eq 'save' ) { Link Here
45
        my $params = {
45
        my $params = {
46
            branchcode      => $branchcode,
46
            branchcode      => $branchcode,
47
            enabled         => scalar $input->param("enable-$branchcode") || 0,
47
            enabled         => scalar $input->param("enable-$branchcode") || 0,
48
            enable_waiting_holds_only => scalar $input->param("enable-waiting-holds-only-$branchcode") || 0,
48
            pickup_interval => scalar $input->param("interval-$branchcode"),
49
            pickup_interval => scalar $input->param("interval-$branchcode"),
49
            patrons_per_interval    => scalar $input->param("max-per-interval-$branchcode"),
50
            patrons_per_interval    => scalar $input->param("max-per-interval-$branchcode"),
50
            patron_scheduled_pickup => scalar $input->param("patron-scheduled-$branchcode") || 0,
51
            patron_scheduled_pickup => scalar $input->param("patron-scheduled-$branchcode") || 0,
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/curbside_pickup.tt (+10 lines)
Lines 112-117 Link Here
112
                                    [% END %]
112
                                    [% END %]
113
                                    <span class="hint">Enable patrons to schedule their own curbside pickups.</span>
113
                                    <span class="hint">Enable patrons to schedule their own curbside pickups.</span>
114
                                </li>
114
                                </li>
115
116
                                <li>
117
                                    <label for="enable-waiting-holds-only-[% l.branchcode | html %]">Enable for waiting holds only: </label>
118
                                    [% IF policies.$branchcode.enable_waiting_holds_only %]
119
                                        <input name="enable-waiting-holds-only-[% l.branchcode | html %]" id="enable-waiting-holds-only-[% l.branchcode | html %]" value="1" type="checkbox" checked>
120
                                    [% ELSE %]
121
                                        <input name="enable-waiting-holds-only-[% l.branchcode | html %]" id="enable-waiting-holds-only-[% l.branchcode | html %]" value="1" type="checkbox">
122
                                    [% END %]
123
                                    <span class="hint">Enable only if the patron has waiting holds.</span>
124
                                </li>
115
                            </ol>
125
                            </ol>
116
                        </fieldset>
126
                        </fieldset>
117
127
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/curbside_pickups.tt (-20 / +22 lines)
Lines 433-455 Link Here
433
                                <button type="submit" class="btn btn-default">Submit</button>
433
                                <button type="submit" class="btn btn-default">Submit</button>
434
                            </form>
434
                            </form>
435
                        [% ELSE %]
435
                        [% ELSE %]
436
                            <form id="create-pickup" method="post" class="form-horizontal">
436
                            [% SET waiting_holds = patron.holds.search( found => 'W', branchcode => logged_in_user.branchcode ) %]
437
                                <fieldset class="rows" style="float: none;">
437
                            [% IF !policy.enable_waiting_holds_only || waiting_holds.count > 0 %]
438
                                    <input type="hidden" name="borrowernumber" value="[% patron.id | html %]"/>
438
                                <form id="create-pickup" method="post">
439
                                    <input type="hidden" name="op" value="create-pickup"/>
439
                                    <fieldset class="rows" style="float: none;">
440
                                    <input type="hidden" name="tab" value="schedule-pickup"/>
440
                                        <input type="hidden" name="borrowernumber" value="[% patron.id | html %]"/>
441
                                    <ol>
441
                                        <input type="hidden" name="op" value="create-pickup"/>
442
                                        <li>
442
                                        <input type="hidden" name="tab" value="schedule-pickup"/>
443
                                            <label>Patron: </label>
443
                                        <ol>
444
                                            <span>[% INCLUDE 'patron-title.inc' patron=patron %]</span>
444
                                            <li>
445
                                        </li>
445
                                                <label>Patron: </label>
446
446
                                                <span>[% INCLUDE 'patron-title.inc' patron=patron %]</span>
447
                                        <li>
447
                                            </li>
448
                                            <label>Items ready for pickup: </label>
448
449
                                            <span>
449
                                            <li>
450
                                                [% SET waiting_holds = patron.holds.search( found => 'W', branchcode => logged_in_user.branchcode ) %]
450
                                                <label>Items ready for pickup: </label>
451
                                                [% IF waiting_holds.count %]
451
                                                <span>
452
                                                    [% FOREACH h IN waiting_holds %]
452
                                                    [% IF waiting_holds.count %]
453
                                                        [% FOREACH h IN waiting_holds %]
453
                                                            <p>
454
                                                            <p>
454
                                                                <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% h.biblionumber | uri %]">[% h.biblio.title | html %]</a> ([% h.biblio.author | html %], <a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% h.itemnumber | html %]&biblionumber=[% h.biblionumber | html %]#item[% h.itemnumber | html %]">[% h.item.barcode | html %]</a>)
455
                                                                <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% h.biblionumber | uri %]">[% h.biblio.title | html %]</a> ([% h.biblio.author | html %], <a href="/cgi-bin/koha/catalogue/moredetail.pl?itemnumber=[% h.itemnumber | html %]&biblionumber=[% h.biblionumber | html %]#item[% h.itemnumber | html %]">[% h.item.barcode | html %]</a>)
455
                                                            </p>
456
                                                            </p>
Lines 477-491 Link Here
477
                                    <fieldset class="action">
478
                                    <fieldset class="action">
478
                                        <input id="schedule-pickup-button" type="submit" value="Submit" />
479
                                        <input id="schedule-pickup-button" type="submit" value="Submit" />
479
                                    </fieldset>
480
                                    </fieldset>
480
481
                                </form>
481
                                </form>
482
                            [% ELSE %]
483
                                <div class="dialog alert">The patron does not have waitings holds.</div>
482
                            [% END %]
484
                            [% END %]
483
                        </div>
485
                        [% END %]
484
                    </div>
486
                    </div>
485
                </div>
487
                </div>
486
            </main>
488
            </main>
487
        </div>
489
        </div>
488
     </div> <!-- /.row -->
490
    </div> <!-- /.row -->
489
491
490
[% MACRO jsinclude BLOCK %]
492
[% MACRO jsinclude BLOCK %]
491
    [% Asset.js("lib/dayjs/dayjs.min.js") | $raw %]
493
    [% Asset.js("lib/dayjs/dayjs.min.js") | $raw %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-curbside-pickups.tt (+15 lines)
Lines 200-205 Link Here
200
            map[e.branchcode] = e;
200
            map[e.branchcode] = e;
201
            return map;
201
            return map;
202
        }, {});
202
        }, {});
203
        let can_schedule_at = {};
203
        [% FOR p IN policies %]
204
        [% FOR p IN policies %]
204
            var opening_slots = [% To.json(p.opening_slots.unblessed) | $raw %];
205
            var opening_slots = [% To.json(p.opening_slots.unblessed) | $raw %];
205
            var slots_per_day = {};
206
            var slots_per_day = {};
Lines 209-214 Link Here
209
                slots_per_day[day].push(slot);
210
                slots_per_day[day].push(slot);
210
            });
211
            });
211
            policies['[% p.branchcode | html %]'].slots_per_day = slots_per_day;
212
            policies['[% p.branchcode | html %]'].slots_per_day = slots_per_day;
213
214
            [% IF p.enable_waiting_holds_only %]
215
                [% SET waiting_holds = logged_in_user.holds.search( found => 'W', branchcode => p.branchcode ) %]
216
                [% UNLESS waiting_holds.count %]
217
                    policies['[% p.branchcode | html %]'].enabled = 0;
218
                [% END %]
219
            [% END %]
212
        [% END %]
220
        [% END %]
213
221
214
        let existingPickupMoments = [];
222
        let existingPickupMoments = [];
Lines 220-225 Link Here
220
            existingPickupMoments[pickup.branchcode].push(pickupMoment);
228
            existingPickupMoments[pickup.branchcode].push(pickupMoment);
221
        });
229
        });
222
230
231
        $("#pickup-branch option").each(function(){
232
            if ( $(this).val() != "" && !policies[$(this).val()].enabled ) {
233
                $(this).prop("disabled", "disabled");
234
                $(this).attr("title", _("You don't have waiting holds at this location"));
235
            }
236
        });
237
223
        $('#pickup-branch').on('change', function() {
238
        $('#pickup-branch').on('change', function() {
224
            let branchcode = $(this).val();
239
            let branchcode = $(this).val();
225
240
(-)a/t/db_dependent/Koha/CurbsidePickups.t (-37 / +25 lines)
Lines 54-59 my $policy = Koha::CurbsidePickupPolicy->new( Link Here
54
    {
54
    {
55
        branchcode              => $library->branchcode,
55
        branchcode              => $library->branchcode,
56
        enabled                 => 1,
56
        enabled                 => 1,
57
        enable_waiting_holds_only => 0,
57
        pickup_interval         => 30,
58
        pickup_interval         => 30,
58
        patrons_per_interval    => 2,
59
        patrons_per_interval    => 2,
59
        patron_scheduled_pickup => 1
60
        patron_scheduled_pickup => 1
Lines 63-68 my $policy_disabled = Koha::CurbsidePickupPolicy->new( Link Here
63
    {
64
    {
64
        branchcode              => $library_disabled->branchcode,
65
        branchcode              => $library_disabled->branchcode,
65
        enabled                 => 0,
66
        enabled                 => 0,
67
        enable_waiting_holds_only => 0,
66
        pickup_interval         => 30,
68
        pickup_interval         => 30,
67
        patrons_per_interval    => 2,
69
        patrons_per_interval    => 2,
68
        patron_scheduled_pickup => 1
70
        patron_scheduled_pickup => 1
Lines 75-106 $policy->add_opening_slot('1-12:00-18:00'); Link Here
75
my $today = dt_from_string;
77
my $today = dt_from_string;
76
78
77
subtest 'Create a pickup' => sub {
79
subtest 'Create a pickup' => sub {
78
    plan tests => 5;
80
    plan tests => 7;
79
81
80
    # Day and datetime are ok
82
    # Day and datetime are ok
81
    my $next_monday =
83
    my $next_monday =
82
      $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
84
      $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
83
    my $schedule_dt =
85
    my $schedule_dt =
84
      $next_monday->set_hour(15)->set_minute(00)->set_second(00);
86
      $next_monday->set_hour(15)->set_minute(00)->set_second(00);
85
    my $cp = Koha::CurbsidePickup->new(
87
    my $params =
86
        {
88
        {
87
            branchcode                => $library->branchcode,
89
            branchcode                => $library->branchcode,
88
            borrowernumber            => $patron->borrowernumber,
90
            borrowernumber            => $patron->borrowernumber,
89
            scheduled_pickup_datetime => $schedule_dt,
91
            scheduled_pickup_datetime => $schedule_dt,
90
            notes                     => 'just a note'
92
            notes                     => 'just a note'
91
        }
93
        };
92
    )->store;
94
95
    throws_ok {
96
        Koha::CurbsidePickup->new({%$params, branchcode => $library_disabled->branchcode})->store;
97
    }
98
    'Koha::Exceptions::CubsidePickup::NotEnabled',
99
      'Cannot create pickup if the policy does not allow it';
100
101
    $policy->enable_waiting_holds_only(1)->store;
102
    throws_ok {
103
        Koha::CurbsidePickup->new($params)->store;
104
    }
105
    'Koha::Exceptions::CubsidePickup::NoWaitingHolds',
106
      'Cannot create pickup for a patron without waiting hold if flag is set';
107
108
    $policy->enable_waiting_holds_only(0)->store;
109
    my $cp = Koha::CurbsidePickup->new($params)->store;
93
    is( $cp->status, 'to-be-staged' );
110
    is( $cp->status, 'to-be-staged' );
94
111
95
    throws_ok {
112
    throws_ok {
96
        Koha::CurbsidePickup->new(
113
        Koha::CurbsidePickup->new($params)->store
97
            {
98
                branchcode                => $library->branchcode,
99
                borrowernumber            => $patron->borrowernumber,
100
                scheduled_pickup_datetime => $schedule_dt,
101
                notes                     => 'just a note'
102
            }
103
          )->store
104
    }
114
    }
105
    'Koha::Exceptions::CubsidePickup::TooManyPickups',
115
    'Koha::Exceptions::CubsidePickup::TooManyPickups',
106
      'Cannot create 2 pickups for the same patron';
116
      'Cannot create 2 pickups for the same patron';
Lines 112-125 subtest 'Create a pickup' => sub { Link Here
112
      $today->clone->add( days => ( 2 - $today->day_of_week ) % 7 );
122
      $today->clone->add( days => ( 2 - $today->day_of_week ) % 7 );
113
    $schedule_dt = $next_tuesday->set_hour(15)->set_minute(00)->set_second(00);
123
    $schedule_dt = $next_tuesday->set_hour(15)->set_minute(00)->set_second(00);
114
    throws_ok {
124
    throws_ok {
115
        Koha::CurbsidePickup->new(
125
        Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
116
            {
117
                branchcode                => $library->branchcode,
118
                borrowernumber            => $patron->borrowernumber,
119
                scheduled_pickup_datetime => $schedule_dt,
120
                notes                     => 'just a note'
121
            }
122
          )->store
123
    }
126
    }
124
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
127
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
125
      'Cannot create a pickup on a day without opening slots defined';
128
      'Cannot create a pickup on a day without opening slots defined';
Lines 127-140 subtest 'Create a pickup' => sub { Link Here
127
    # Day ok but datetime not ok
130
    # Day ok but datetime not ok
128
    $schedule_dt = $next_monday->set_hour(19)->set_minute(00)->set_second(00);
131
    $schedule_dt = $next_monday->set_hour(19)->set_minute(00)->set_second(00);
129
    throws_ok {
132
    throws_ok {
130
        Koha::CurbsidePickup->new(
133
        Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
131
            {
132
                branchcode                => $library->branchcode,
133
                borrowernumber            => $patron->borrowernumber,
134
                scheduled_pickup_datetime => $schedule_dt,
135
                notes                     => 'just a note'
136
            }
137
          )->store
138
    }
134
    }
139
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
135
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
140
      'Cannot create a pickup on a time without opening slots defined';
136
      'Cannot create a pickup on a time without opening slots defined';
Lines 142-155 subtest 'Create a pickup' => sub { Link Here
142
    # Day ok, datetime inside the opening slot, but wrong (15:15 for instance)
138
    # Day ok, datetime inside the opening slot, but wrong (15:15 for instance)
143
    $schedule_dt = $next_monday->set_hour(15)->set_minute(15)->set_second(00);
139
    $schedule_dt = $next_monday->set_hour(15)->set_minute(15)->set_second(00);
144
    throws_ok {
140
    throws_ok {
145
        Koha::CurbsidePickup->new(
141
        Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
146
            {
147
                branchcode                => $library->branchcode,
148
                borrowernumber            => $patron->borrowernumber,
149
                scheduled_pickup_datetime => $schedule_dt,
150
                notes                     => 'just a note'
151
            }
152
          )->store
153
    }
142
    }
154
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
143
    'Koha::Exceptions::CubsidePickup::NoMatchingSlots',
155
'Cannot create a pickup on a time that is not matching the start of an interval';
144
'Cannot create a pickup on a time that is not matching the start of an interval';
156
- 

Return to bug 30650