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

(-)a/C4/Reserves.pm (-16 / +32 lines)
Lines 193-198 sub AddReserve { Link Here
193
    my $found          = $params->{found};
193
    my $found          = $params->{found};
194
    my $itemtype       = $params->{itemtype};
194
    my $itemtype       = $params->{itemtype};
195
    my $non_priority   = $params->{non_priority};
195
    my $non_priority   = $params->{non_priority};
196
    my $hold_group_id  = $params->{hold_group_id};
196
197
197
    $resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' })
198
    $resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' })
198
        or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' });
199
        or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' });
Lines 255-260 sub AddReserve { Link Here
255
            itemtype       => $itemtype,
256
            itemtype       => $itemtype,
256
            item_level_hold => $checkitem ? 1 : 0,
257
            item_level_hold => $checkitem ? 1 : 0,
257
            non_priority   => $non_priority ? 1 : 0,
258
            non_priority   => $non_priority ? 1 : 0,
259
            hold_group_id  => $hold_group_id,
258
        }
260
        }
259
    )->store();
261
    )->store();
260
    $hold->set_waiting() if $found && $found eq 'W';
262
    $hold->set_waiting() if $found && $found eq 'W';
Lines 520-537 sub CanItemBeReserved { Link Here
520
                biblionumber   => $item->biblionumber,
522
                biblionumber   => $item->biblionumber,
521
            };
523
            };
522
            $search_params->{found} = undef if $params->{ignore_found_holds};
524
            $search_params->{found} = undef if $params->{ignore_found_holds};
523
            my $holds = Koha::Holds->search($search_params);
525
            my $holds_count = Koha::Holds->count_holds($search_params);
524
            return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record;
526
            return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds_count >= $holds_per_record;
525
        }
527
        }
526
    }
528
    }
527
529
528
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
530
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '')
529
    {
531
    {
530
        my $today_holds = Koha::Holds->search({
532
        my $today_holds_count = Koha::Holds->count_holds({
531
            borrowernumber => $patron->borrowernumber,
533
            borrowernumber => $patron->borrowernumber,
532
            reservedate    => dt_from_string->date
534
            reservedate    => dt_from_string->date
533
        });
535
        });
534
        return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day;
536
        return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds_count >= $holds_per_day;
535
    }
537
    }
536
538
537
    # we check if it's ok or not
539
    # we check if it's ok or not
Lines 1235-1240 sub ModReserveAffect { Link Here
1235
1237
1236
    $hold->itemnumber($itemnumber);
1238
    $hold->itemnumber($itemnumber);
1237
1239
1240
    my @reserve_ids;
1241
    push @reserve_ids, $hold->reserve_id;
1242
1238
    if ($transferToDo) {
1243
    if ($transferToDo) {
1239
        $hold->set_transfer();
1244
        $hold->set_transfer();
1240
    } elsif (C4::Context->preference('HoldsNeedProcessingSIP')
1245
    } elsif (C4::Context->preference('HoldsNeedProcessingSIP')
Lines 1247-1252 sub ModReserveAffect { Link Here
1247
        # Complete transfer if one exists
1252
        # Complete transfer if one exists
1248
        my $transfer = $hold->item->get_transfer;
1253
        my $transfer = $hold->item->get_transfer;
1249
        $transfer->receive if $transfer;
1254
        $transfer->receive if $transfer;
1255
1256
        # if this hold was part of a group, cancel other holds in the group
1257
        if ( $hold->hold_group_id ) {
1258
            my @holds = $hold->hold_group->holds->as_list;
1259
            foreach my $h ( @holds ) {
1260
                push @reserve_ids, $h->reserve_id;
1261
                $h->cancel unless $h->reserve_id == $hold->reserve_id;
1262
            }
1263
        }
1250
    }
1264
    }
1251
1265
1252
    _koha_notify_hold_changed( $hold ) if $notify_library;
1266
    _koha_notify_hold_changed( $hold ) if $notify_library;
Lines 1258-1275 sub ModReserveAffect { Link Here
1258
      CartToShelf( $itemnumber );
1272
      CartToShelf( $itemnumber );
1259
    }
1273
    }
1260
1274
1261
    my $std = $dbh->prepare(q{
1275
    foreach my $id ( @reserve_ids ) {
1262
        DELETE  q, t
1276
        my $std = $dbh->prepare(q{
1263
        FROM    tmp_holdsqueue q
1277
            DELETE  q, t
1264
        INNER JOIN hold_fill_targets t
1278
            FROM    tmp_holdsqueue q
1265
        ON  q.borrowernumber = t.borrowernumber
1279
            INNER JOIN hold_fill_targets t
1266
            AND q.biblionumber = t.biblionumber
1280
            ON  q.borrowernumber = t.borrowernumber
1267
            AND q.itemnumber = t.itemnumber
1281
                AND q.biblionumber = t.biblionumber
1268
            AND q.item_level_request = t.item_level_request
1282
                AND q.itemnumber = t.itemnumber
1269
            AND q.holdingbranch = t.source_branchcode
1283
                AND q.item_level_request = t.item_level_request
1270
        WHERE t.reserve_id = ?
1284
                AND q.holdingbranch = t.source_branchcode
1271
    });
1285
            WHERE t.reserve_id = ?
1272
    $std->execute($hold->reserve_id);
1286
        });
1287
        $std->execute($id);
1288
    }
1273
1289
1274
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, $hold )
1290
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, $hold )
1275
        if C4::Context->preference('HoldsLog');
1291
        if C4::Context->preference('HoldsLog');
(-)a/Koha/Hold.pm (+28 lines)
Lines 41-46 use Koha::Plugins; Link Here
41
use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
41
use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
42
42
43
use Koha::Exceptions;
43
use Koha::Exceptions;
44
use Koha::HoldGroups;
44
use Koha::Exceptions::Hold;
45
use Koha::Exceptions::Hold;
45
46
46
use base qw(Koha::Object);
47
use base qw(Koha::Object);
Lines 796-801 sub fill { Link Here
796
            C4::Log::logaction( 'HOLDS', 'FILL', $self->id, $self )
797
            C4::Log::logaction( 'HOLDS', 'FILL', $self->id, $self )
797
                if C4::Context->preference('HoldsLog');
798
                if C4::Context->preference('HoldsLog');
798
799
800
            # if this hold was part of a group, cancel other holds in the group
801
            if ( $self->hold_group_id ) {
802
                my @holds = $self->hold_group->holds->as_list;
803
                foreach my $h ( @holds ) {
804
                    $h->cancel unless $h->reserve_id == $self->id;
805
                }
806
            }
807
799
            Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue(
808
            Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue(
800
                {
809
                {
801
                    biblio_ids => [ $old_me->biblionumber ]
810
                    biblio_ids => [ $old_me->biblionumber ]
Lines 861-866 sub _set_default_expirationdate { Link Here
861
        dt_from_string( $self->reservedate )->add( $timeunit => $period ) );
870
        dt_from_string( $self->reservedate )->add( $timeunit => $period ) );
862
}
871
}
863
872
873
=head3 hold_group
874
875
    my $hold_group = $hold->hold_group;
876
    my $hold_group_id = $hold_group->id if $hold_group;
877
878
Return the Koha::HoldGroup object of a hold if part of a hold group
879
880
=cut
881
882
sub hold_group {
883
    my ( $self ) = @_;
884
885
    if ( $self->hold_group_id ) {
886
        return Koha::HoldGroups->find( $self->hold_group_id );
887
    }
888
889
    return;
890
}
891
864
=head3 _move_to_old
892
=head3 _move_to_old
865
893
866
my $is_moved = $hold->_move_to_old;
894
my $is_moved = $hold->_move_to_old;
(-)a/Koha/HoldGroup.pm (+63 lines)
Line 0 Link Here
1
package Koha::HoldGroup;
2
3
# Copyright 2020 Koha Development team
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use base qw(Koha::Object);
23
24
=head1 NAME
25
26
Koha::HoldGroup - Koha Hold Group object class
27
28
=head1 API
29
30
=head2 Class Methods
31
32
=cut
33
34
=head3 holds
35
36
    $holds = $hold_group->holds
37
38
Return all holds associated with this group
39
40
=cut
41
42
sub holds {
43
    my ($self) = @_;
44
45
    my $holds_rs = $self->_result->reserves->search;
46
    return Koha::Holds->_new_from_dbic($holds_rs);
47
}
48
49
=head3 _type
50
51
=cut
52
53
sub _type {
54
    return 'HoldGroup';
55
}
56
57
=head1 AUTHORS
58
59
Josef Moravec <josef.moravec@gmail.com>
60
61
=cut
62
63
1;
(-)a/Koha/HoldGroups.pm (+60 lines)
Line 0 Link Here
1
package Koha::HoldGroups;
2
3
# Copyright Koha Development team 2020
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Koha::Database;
23
24
use Koha::HoldGroup;
25
26
use base qw(Koha::Objects);
27
28
=head1 NAME
29
30
Koha::HoldGroups - Koha Hold Group object set class
31
32
=head1 API
33
34
=head2 Class Methods
35
36
=cut
37
38
=head3 _type
39
40
=cut
41
42
sub _type {
43
    return 'HoldGroup';
44
}
45
46
=head3 object_class
47
48
=cut
49
50
sub object_class {
51
    return 'Koha::HoldGroup';
52
}
53
54
=head1 AUTHOR
55
56
Josef Moravec <josef.moravec@gmail.com>
57
58
=cut
59
60
1;
(-)a/Koha/Holds.pm (+26 lines)
Lines 178-183 sub filter_out_has_cancellation_requests { Link Here
178
        { join => 'cancellation_requests' } );
178
        { join => 'cancellation_requests' } );
179
}
179
}
180
180
181
=head3 count
182
183
    $holds->count( $search_params );
184
185
This overwrites the default count().
186
187
Return the number of holds, where a hold group is counted as one hold.
188
189
=cut
190
191
sub count_holds {
192
    my ( $self, $search_params ) = @_;
193
194
    $search_params = {
195
        hold_group_id => undef,
196
    };
197
    my $holds_without_group_count = $self->search( $search_params )->count();
198
199
    $search_params = {
200
        hold_group_id => { '!=', undef },
201
    };
202
    my $hold_groups_count = $self->search( $search_params, { group_by => 'me.hold_group_id' })->count();
203
204
    return $holds_without_group_count + $hold_groups_count;
205
}
206
181
=head2 Internal methods
207
=head2 Internal methods
182
208
183
=head3 _type
209
=head3 _type
(-)a/t/db_dependent/Koha/Holds.t (-1 / +71 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 8;
22
use Test::More tests => 9;
23
use Test::Warn;
23
use Test::Warn;
24
24
25
use C4::Circulation qw( AddIssue );
25
use C4::Circulation qw( AddIssue );
Lines 641-646 subtest 'set_waiting+patron_expiration_date' => sub { Link Here
641
    };
641
    };
642
};
642
};
643
643
644
subtest 'count_holds' => sub {
645
    plan tests => 3;
646
    $schema->storage->txn_begin;
647
648
    my $patron = $builder->build_object({
649
        class => 'Koha::Patrons',
650
    });
651
    my $patron_id = $patron->borrowernumber;
652
653
    my $hold1 = $builder->build_object({
654
            class => 'Koha::Holds',
655
            value => {
656
                borrowernumber => $patron_id,
657
                hold_group_id => undef,
658
            },
659
        });
660
661
    is($patron->holds->count_holds, 1, 'Test patron has 1 hold.');
662
663
    my $hold_group = $builder->build_object({
664
        class => 'Koha::HoldGroups',
665
    });
666
667
    my $hold2 = $builder->build_object({
668
        class => 'Koha::Holds',
669
        value => {
670
            borrowernumber => $patron_id,
671
            hold_group_id => $hold_group->hold_group_id,
672
        }
673
    });
674
    my $hold3 = $builder->build_object({
675
        class => 'Koha::Holds',
676
        value => {
677
            borrowernumber => $patron_id,
678
            hold_group_id => $hold_group->hold_group_id,
679
        }
680
    });
681
682
    is($patron->holds->count_holds, 2, 'Test patron has 2 holds.');
683
684
    my $hold_group2 = $builder->build_object({
685
        class => 'Koha::HoldGroups',
686
    });
687
688
    my $hold4 = $builder->build_object({
689
        class => 'Koha::Holds',
690
        value => {
691
            borrowernumber => $patron_id,
692
            hold_group_id => $hold_group2->hold_group_id,
693
        }
694
    });
695
    my $hold5 = $builder->build_object({
696
        class => 'Koha::Holds',
697
        value => {
698
            borrowernumber => $patron_id,
699
            hold_group_id => $hold_group2->hold_group_id,
700
        }
701
    });
702
    my $hold6 = $builder->build_object({
703
        class => 'Koha::Holds',
704
        value => {
705
            borrowernumber => $patron_id,
706
            hold_group_id => $hold_group2->hold_group_id,
707
        }
708
    });
709
710
    is($patron->holds->count_holds, 3, 'Test patron has 3 holds.');
711
712
    $schema->storage->txn_rollback;
713
};
644
714
645
$schema->storage->txn_rollback;
715
$schema->storage->txn_rollback;
646
716
(-)a/t/db_dependent/Reserves/HoldGroup.t (-1 / +53 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2020 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More tests => 1;
23
24
use t::lib::TestBuilder;
25
26
my $schema  = Koha::Database->new->schema;
27
my $builder = t::lib::TestBuilder->new;
28
29
subtest 'holds tests' => sub {
30
31
    plan tests => 2;
32
33
    $schema->storage->txn_begin;
34
35
    my $patron     = $builder->build_object({ class => 'Koha::Patrons' });
36
    my $hold_group = $builder->build_object({ class => 'Koha::HoldGroups' });
37
    my $hold       = $builder->build_object(
38
        {
39
            class => 'Koha::Holds',
40
            value => {
41
                borrowernumber => $patron->borrowernumber,
42
                hold_group_id  => $hold_group->hold_group_id,
43
            }
44
        }
45
    );
46
47
    my $holds = $hold_group->holds;
48
    is( ref($holds), 'Koha::Holds', 'Right type' );
49
    my $hold_from_group = $holds->next;
50
    is( $hold_from_group->id, $hold->id, 'Right object' );
51
52
    $schema->storage->txn_rollback;
53
};

Return to bug 15516