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

(-)a/installer/data/mysql/atomicupdate/bug_32776_-_add_ConvertSelectedHoldsToRecalls_syspref.pl (-4 / +6 lines)
Lines 1-13 Link Here
1
use Modern::Perl;
1
use Modern::Perl;
2
2
3
return {
3
return {
4
    bug_number => "32776",
4
    bug_number  => "32776",
5
    description => "Convert selected reserves to recalls",
5
    description => "Convert selected reserves to recalls",
6
    up => sub {
6
    up          => sub {
7
        my ($args) = @_;
7
        my ($args) = @_;
8
        my ($dbh, $out) = @$args{qw(dbh out)};
8
        my ( $dbh, $out ) = @$args{qw(dbh out)};
9
9
10
        $dbh->do(q{INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('ConvertSelectedHoldsToRecalls', 'oldest', 'oldest|recallable', 'Choose whether the convert_reserves_to_recalls.pl cronjob should convert only the oldest reserve on the record to a recall, or one reserve for each item available to be recalled', 'Choice') });
10
        $dbh->do(
11
            q{INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('ConvertSelectedHoldsToRecalls', 'oldest', 'oldest|recallable', 'Choose whether the convert_reserves_to_recalls.pl cronjob should convert only the oldest reserve on the record to a recall, or one reserve for each item available to be recalled', 'Choice') }
12
        );
11
13
12
        say $out "Added system preference 'ConvertSelectedHoldsToRecalls'";
14
        say $out "Added system preference 'ConvertSelectedHoldsToRecalls'";
13
    },
15
    },
(-)a/misc/cronjobs/recalls/convert_holds_to_recalls.pl (-45 / +62 lines)
Lines 46-56 This script converts holds to recalls when a record has a set minimum number of Link Here
46
46
47
If a record is found to have the specified minimum number of holds, the script will find the oldest hold and convert it to a recall, as long as it would be a legal recall.
47
If a record is found to have the specified minimum number of holds, the script will find the oldest hold and convert it to a recall, as long as it would be a legal recall.
48
48
49
This script uses the ConvertedSelectedHoldsToRecalls system preference.
49
This script uses the ConvertSelectedHoldsToRecalls system preference.
50
50
51
When ConvertedSelectedHoldsToRecalls is set to 'oldest', this script will only convert the single oldest hold. Once converted, the script will move on to the next record, it will not continue to convert holds on this record.
51
When ConvertSelectedHoldsToRecalls is set to 'oldest', this script will only convert the single oldest hold. Once converted, the script will move on to the next record, it will not continue to convert holds on this record.
52
52
53
When ConvertedSelectedHoldsToRecalls is set to 'recallable', this script will convert reserves one-by-one, oldest first, until all recallable items have been recalled.
53
When ConvertSelectedHoldsToRecalls is set to 'recallable', this script will convert reserves one-by-one, oldest first, until all recallable items have been recalled.
54
54
55
  Options:
55
  Options:
56
    -v          verbose
56
    -v          verbose
Lines 76-121 my $min = 5; Link Here
76
my $verbose;
76
my $verbose;
77
77
78
GetOptions(
78
GetOptions(
79
    'min|m=i' => \$min,
79
    'min|m=i'   => \$min,
80
    'verbose|v' => \$verbose
80
    'verbose|v' => \$verbose
81
) or pod2usage(1);
81
) or pod2usage(1);
82
82
83
# get holds where there is more than $min holds on one biblio
83
# get holds where there is more than $min holds on one biblio
84
my @bib_holds = Koha::Holds->search({}, {
84
my @bib_holds = Koha::Holds->search(
85
    select => [
85
    {},
86
        'biblionumber',
86
    {
87
        { count => 'biblionumber', -as => 'bibcount' }
87
        select => [
88
    ],
88
            'biblionumber',
89
    group_by => 'biblionumber',
89
            { count => 'biblionumber', -as => 'bibcount' }
90
    having => { 'bibcount' => { '>=', $min } },
90
        ],
91
})->as_list;
91
        group_by => 'biblionumber',
92
        having   => { 'bibcount' => { '>=', $min } },
93
    }
94
)->as_list;
92
95
93
my $count = 0;
96
my $count = 0;
94
foreach my $bib ( @bib_holds ) {
97
foreach my $bib (@bib_holds) {
95
    $bib = $bib->unblessed;
98
    $bib = $bib->unblessed;
99
96
    # If there are $min or more holds on the same record, we can begin converting holds
100
    # If there are $min or more holds on the same record, we can begin converting holds
97
    if ( $bib->{bibcount} >= $min ) {
101
    if ( $bib->{bibcount} >= $min ) {
98
102
99
        # Get all holds on this biblio
103
        # Get all holds on this biblio
100
        my @holds = Koha::Holds->search({ biblionumber => $bib->{biblionumber}, found => undef }, { order_by => { -asc => 'reservedate' } })->as_list;
104
        my @holds = Koha::Holds->search(
105
            { biblionumber => $bib->{biblionumber}, found => undef },
106
            { order_by     => { -asc => 'reservedate' } }
107
        )->as_list;
101
108
102
        if ( C4::Context->preference('ConvertedSelectedHoldsToRecalls') eq 'oldest' ) {
109
        if ( C4::Context->preference('ConvertSelectedHoldsToRecalls') eq 'oldest' ) {
103
110
104
            my $hold_to_convert = $holds[0];
111
            my $hold_to_convert        = $holds[0];
105
            my $itemnumber_to_allocate = can_convert( $hold_to_convert );
112
            my $itemnumber_to_allocate = can_convert($hold_to_convert);
106
            if ( $itemnumber_to_allocate ) {
113
            if ($itemnumber_to_allocate) {
107
                my $item_to_allocate = Koha::Items->find( $itemnumber_to_allocate );
114
                my $item_to_allocate = Koha::Items->find($itemnumber_to_allocate);
108
                do_convert( $hold_to_convert, $item_to_allocate );
115
                do_convert( $hold_to_convert, $item_to_allocate );
109
                report( $hold_to_convert, ++$count );
116
                report( $hold_to_convert, ++$count );
110
            }
117
            }
111
118
112
        } elsif ( C4::Context->preference('ConvertedSelectedHoldsToRecalls') eq 'recallable' ) {
119
        } elsif ( C4::Context->preference('ConvertSelectedHoldsToRecalls') eq 'recallable' ) {
113
120
114
            my $this_record_holds_converted = 0;
121
            my $this_record_holds_converted = 0;
115
122
116
            my @items = Koha::Items->search({ biblionumber => $bib->{biblionumber} })->as_list;
123
            my @items = Koha::Items->search( { biblionumber => $bib->{biblionumber} } )->as_list;
117
            foreach my $item ( @items ) {
124
            foreach my $item (@items) {
118
                my $hold_to_convert = $holds[ $this_record_holds_converted ];
125
                my $hold_to_convert = $holds[$this_record_holds_converted];
119
126
120
                if ( !$hold_to_convert ) {
127
                if ( !$hold_to_convert ) {
121
                    last;
128
                    last;
Lines 123-130 foreach my $bib ( @bib_holds ) { Link Here
123
130
124
                my $itemnumber_to_allocate = can_convert( $hold_to_convert, $item );
131
                my $itemnumber_to_allocate = can_convert( $hold_to_convert, $item );
125
132
126
                if ( $itemnumber_to_allocate ) {
133
                if ($itemnumber_to_allocate) {
127
                    my $item_to_allocate = $itemnumber_to_allocate == $item->id ? $item : Koha::Items->find( $itemnumber_to_allocate );
134
                    my $item_to_allocate =
135
                        $itemnumber_to_allocate == $item->id ? $item : Koha::Items->find($itemnumber_to_allocate);
128
                    do_convert( $hold_to_convert, $item_to_allocate );
136
                    do_convert( $hold_to_convert, $item_to_allocate );
129
                    report( $hold_to_convert, ++$count );
137
                    report( $hold_to_convert, ++$count );
130
                    $this_record_holds_converted++;
138
                    $this_record_holds_converted++;
Lines 144-175 sub can_convert { Link Here
144
    if ( $hold->item_level_hold ) {
152
    if ( $hold->item_level_hold ) {
145
153
146
        if ( $item and $item->id == $hold->itemnumber ) {
154
        if ( $item and $item->id == $hold->itemnumber ) {
155
147
            # item-level reserve, on this specific item
156
            # item-level reserve, on this specific item
148
            if ( $item->can_be_recalled({ patron => $patron, hold_convert => 1 }) ) {
157
            if ( $item->can_be_recalled( { patron => $patron, hold_convert => 1 } ) ) {
149
                return $item->id;
158
                return $item->id;
150
            }
159
            }
151
        } else {
160
        } else {
161
152
            # item-level reserve but not on this item
162
            # item-level reserve but not on this item
153
            # so check if intended item can be allocated for the recall
163
            # so check if intended item can be allocated for the recall
154
            $item = Koha::Items->find( $hold->itemnumber );
164
            $item = Koha::Items->find( $hold->itemnumber );
155
            if ( $item and $item->can_be_recalled({ patron => $patron, hold_convert => 1 }) ) {
165
            if ( $item and $item->can_be_recalled( { patron => $patron, hold_convert => 1 } ) ) {
156
                return $item->id;
166
                return $item->id;
157
            }
167
            }
158
        }
168
        }
159
169
160
    } else {
170
    } else {
171
161
        # bib-level reserve
172
        # bib-level reserve
162
173
163
        if ( $item and $item->can_be_recalled({ patron => $patron, hold_convert => 1 }) and Koha::Recalls->filter_by_current->search({ item_id => $item->id })->count < 1 ) {
174
        if ( C4::Context->preference('ConvertSelectedHoldsToRecalls') eq 'oldest' ) {
164
            # this item may be able to fill the recall
175
            if (    $item
165
            return $item->id;
176
                and $item->can_be_recalled( { patron => $patron, hold_convert => 1 } )
177
                and Koha::Recalls->filter_by_current->search( { item_id => $item->id } )->count < 1 )
178
            {
179
                # this item may be able to fill the recall
180
                return $item->id;
181
            }
166
        }
182
        }
167
183
168
        # don't have a specific item to allocate for this recall
184
        # don't have a specific item to allocate for this recall
169
        # so get an eligible item that's not already recalled
185
        # so get an eligible item that's not already recalled
170
        foreach my $i ( $biblio->items->as_list ) {
186
        foreach my $i ( $biblio->items->as_list ) {
171
            if ( Koha::Recalls->filter_by_current->search({ item_id => $i->id })->count < 1 ) {
187
            if ( Koha::Recalls->filter_by_current->search( { item_id => $i->id } )->count < 1 ) {
172
                if ( $i and $i->can_be_recalled({ patron => $patron, hold_convert => 1 }) ) {
188
                if ( $i and $i->can_be_recalled( { patron => $patron, hold_convert => 1 } ) ) {
173
                    return $i->id;
189
                    return $i->id;
174
                }
190
                }
175
            }
191
            }
Lines 189-211 sub do_convert { Link Here
189
    my $patron = Koha::Patrons->find( $hold->borrowernumber );
205
    my $patron = Koha::Patrons->find( $hold->borrowernumber );
190
    my $biblio = Koha::Biblios->find( $hold->biblionumber );
206
    my $biblio = Koha::Biblios->find( $hold->biblionumber );
191
207
192
    my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
208
    my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall(
193
        patron => $patron,
209
        {
194
        biblio => $biblio,
210
            patron         => $patron,
195
        branchcode => $hold->branchcode,
211
            biblio         => $biblio,
196
        item => $item,
212
            branchcode     => $hold->branchcode,
197
        expirationdate => $hold->patron_expiration_date ? $hold->patron_expiration_date : $hold->expirationdate,
213
            item           => $item,
198
        interface => 'commandline',
214
            expirationdate => $hold->patron_expiration_date ? $hold->patron_expiration_date : $hold->expirationdate,
199
    });
215
            interface      => 'commandline',
200
    $hold->cancel({ cancellation_reason => 'RECALLED' });
216
        }
217
    );
218
    $hold->cancel( { cancellation_reason => 'RECALLED' } );
201
}
219
}
202
220
203
sub report {
221
sub report {
204
    my $hold = shift;
222
    my $hold  = shift;
205
    my $count = shift;
223
    my $count = shift;
206
224
207
    if ( $verbose ) {
225
    if ($verbose) {
208
        my $hold_id = $hold->reserve_id;
226
        my $hold_id      = $hold->reserve_id;
209
        my $biblionumber = $hold->biblionumber;
227
        my $biblionumber = $hold->biblionumber;
210
        print "$count. Hold converted to recall (reserve_id: $hold_id, biblionumber: $biblionumber).\n";
228
        print "$count. Hold converted to recall (reserve_id: $hold_id, biblionumber: $biblionumber).\n";
211
    }
229
    }
212
- 

Return to bug 32776