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

(-)a/C4/Circulation.pm (-2 / +2 lines)
Lines 381-387 sub transferbook { Link Here
381
    }
381
    }
382
382
383
    # find recall
383
    # find recall
384
    my $recall = Koha::Recalls->find({ itemnumber => $itemnumber, status => 'T' });
384
    my $recall = Koha::Recalls->find({ itemnumber => $itemnumber, status => 'in_transit' });
385
    if ( defined $recall and C4::Context->preference('UseRecalls') ) {
385
    if ( defined $recall and C4::Context->preference('UseRecalls') ) {
386
        # do a transfer if the recall branch is different to the item holding branch
386
        # do a transfer if the recall branch is different to the item holding branch
387
        if ( $recall->branchcode eq $fbr ) {
387
        if ( $recall->branchcode eq $fbr ) {
Lines 2354-2360 sub AddReturn { Link Here
2354
        $request->status('RET') if $request;
2354
        $request->status('RET') if $request;
2355
    }
2355
    }
2356
2356
2357
    my $transfer_recall = Koha::Recalls->find({ itemnumber => $item->itemnumber, status => 'T' }); # all recalls that have triggered a transfer will have an allocated itemnumber
2357
    my $transfer_recall = Koha::Recalls->find({ itemnumber => $item->itemnumber, status => 'in_transit' }); # all recalls that have triggered a transfer will have an allocated itemnumber
2358
    if ( $transfer_recall and
2358
    if ( $transfer_recall and
2359
         $transfer_recall->branchcode eq $branch and
2359
         $transfer_recall->branchcode eq $branch and
2360
         C4::Context->preference('UseRecalls') ) {
2360
         C4::Context->preference('UseRecalls') ) {
(-)a/C4/Overdues.pm (-1 / +1 lines)
Lines 260-266 sub CalcFine { Link Here
260
260
261
        # check if item has been recalled. recall should have been marked Overdue by cronjob, so only look at overdue recalls
261
        # check if item has been recalled. recall should have been marked Overdue by cronjob, so only look at overdue recalls
262
        # only charge using recall_overdue_fine if there is an item-level recall for this particular item, OR a biblio-level recall
262
        # only charge using recall_overdue_fine if there is an item-level recall for this particular item, OR a biblio-level recall
263
        my @recalls = Koha::Recalls->search({ biblionumber => $item->{biblionumber}, old => undef, status => 'O' })->as_list;
263
        my @recalls = Koha::Recalls->search({ biblionumber => $item->{biblionumber}, old => undef, status => 'overdue' })->as_list;
264
        my $bib_level_recall = 0;
264
        my $bib_level_recall = 0;
265
        $bib_level_recall = 1 if scalar @recalls > 0;
265
        $bib_level_recall = 1 if scalar @recalls > 0;
266
        foreach my $recall ( @recalls ) {
266
        foreach my $recall ( @recalls ) {
(-)a/C4/XSLT.pm (-1 / +1 lines)
Lines 354-360 sub buildKohaItemsNamespace { Link Here
354
        my $status;
354
        my $status;
355
        my $substatus = '';
355
        my $substatus = '';
356
356
357
        my $recalls = Koha::Recalls->search({ itemnumber => $item->itemnumber, status => 'W' });
357
        my $recalls = Koha::Recalls->search({ itemnumber => $item->itemnumber, status => 'waiting' });
358
358
359
        if ( $recalls->count ) {
359
        if ( $recalls->count ) {
360
            # recalls take priority over holds
360
            # recalls take priority over holds
(-)a/Koha/Item.pm (-1 / +3 lines)
Lines 1608-1614 Get the most relevant recall for this item. Link Here
1608
sub check_recalls {
1608
sub check_recalls {
1609
    my ( $self ) = @_;
1609
    my ( $self ) = @_;
1610
1610
1611
    my @recalls = Koha::Recalls->search({ biblionumber => $self->biblionumber, itemnumber => [ $self->itemnumber, undef ], status => [ 'R','O','W','T' ] }, { order_by => { -asc => 'recalldate' } })->as_list;
1611
    my @recalls =
1612
      Koha::Recalls->search( { biblionumber => $self->biblionumber, itemnumber => [ $self->itemnumber, undef ], status => [ 'requested', 'overdue', 'waiting', 'in_transit' ] },
1613
        { order_by => { -asc => 'recalldate' } } )->as_list;
1612
1614
1613
    my $recall;
1615
    my $recall;
1614
    # iterate through relevant recalls to find the best one.
1616
    # iterate through relevant recalls to find the best one.
(-)a/Koha/Recall.pm (-38 / +32 lines)
Lines 144-151 Return true if recall status is requested. Link Here
144
144
145
sub requested {
145
sub requested {
146
    my ( $self ) = @_;
146
    my ( $self ) = @_;
147
    my $status = $self->status;
147
    return $self->status eq 'requested';
148
    return $status && $status eq 'R';
149
}
148
}
150
149
151
=head3 waiting
150
=head3 waiting
Lines 160-167 Return true if recall is awaiting pickup. Link Here
160
159
161
sub waiting {
160
sub waiting {
162
    my ( $self ) = @_;
161
    my ( $self ) = @_;
163
    my $status = $self->status;
162
    return $self->status eq 'waiting';
164
    return $status && $status eq 'W';
165
}
163
}
166
164
167
=head3 overdue
165
=head3 overdue
Lines 176-183 Return true if recall is overdue to be returned. Link Here
176
174
177
sub overdue {
175
sub overdue {
178
    my ( $self ) = @_;
176
    my ( $self ) = @_;
179
    my $status = $self->status;
177
    return $self->status eq 'overdue';
180
    return $status && $status eq 'O';
181
}
178
}
182
179
183
=head3 in_transit
180
=head3 in_transit
Lines 192-199 Return true if recall is in transit. Link Here
192
189
193
sub in_transit {
190
sub in_transit {
194
    my ( $self ) = @_;
191
    my ( $self ) = @_;
195
    my $status = $self->status;
192
    return $self->status eq 'in_transit';
196
    return $status && $status eq 'T';
197
}
193
}
198
194
199
=head3 expired
195
=head3 expired
Lines 208-215 Return true if recall has expired. Link Here
208
204
209
sub expired {
205
sub expired {
210
    my ( $self ) = @_;
206
    my ( $self ) = @_;
211
    my $status = $self->status;
207
    return $self->status eq 'expired';
212
    return $status && $status eq 'E';
213
}
208
}
214
209
215
=head3 cancelled
210
=head3 cancelled
Lines 224-247 Return true if recall has been cancelled. Link Here
224
219
225
sub cancelled {
220
sub cancelled {
226
    my ( $self ) = @_;
221
    my ( $self ) = @_;
227
    my $status = $self->status;
222
    return $self->status eq 'cancelled';
228
    return $status && $status eq 'C';
229
}
223
}
230
224
231
=head3 finished
225
=head3 fulfilled
232
226
233
    if ( $recall->finished )
227
    if ( $recall->fulfilled )
234
228
235
    [% IF recall.finished %]
229
    [% IF recall.fulfilled %]
236
230
237
Return true if recall is finished and has been fulfilled.
231
Return true if the recall has been fulfilled.
238
232
239
=cut
233
=cut
240
234
241
sub finished {
235
sub fulfilled {
242
    my ( $self ) = @_;
236
    my ( $self ) = @_;
243
    my $status = $self->status;
237
    return $self->status eq 'fulfilled';
244
    return $status && $status eq 'F';
245
}
238
}
246
239
247
=head3 calc_expirationdate
240
=head3 calc_expirationdate
Lines 294-303 sub start_transfer { Link Here
294
287
295
    if ( $self->item_level_recall ) {
288
    if ( $self->item_level_recall ) {
296
        # already has an itemnumber
289
        # already has an itemnumber
297
        $self->update({ status => 'T' });
290
        $self->update({ status => 'in_transit' });
298
    } else {
291
    } else {
299
        my $itemnumber = $params->{item}->itemnumber;
292
        my $itemnumber = $params->{item}->itemnumber;
300
        $self->update({ status => 'T', itemnumber => $itemnumber });
293
        $self->update({ status => 'in_transit', itemnumber => $itemnumber });
301
    }
294
    }
302
295
303
    my ( $dotransfer, $messages ) = C4::Circulation::transferbook({ to_branch => $self->branchcode, from_branch => $self->item->holdingbranch, barcode => $self->item->barcode, trigger => 'Recall' });
296
    my ( $dotransfer, $messages ) = C4::Circulation::transferbook({ to_branch => $self->branchcode, from_branch => $self->item->holdingbranch, barcode => $self->item->barcode, trigger => 'Recall' });
Lines 317-325 sub revert_transfer { Link Here
317
    my ( $self ) = @_;
310
    my ( $self ) = @_;
318
311
319
    if ( $self->item_level_recall ) {
312
    if ( $self->item_level_recall ) {
320
        $self->update({ status => 'R' });
313
        $self->update({ status => 'requested' });
321
    } else {
314
    } else {
322
        $self->update({ status => 'R', itemnumber => undef });
315
        $self->update({ status => 'requested', itemnumber => undef });
323
    }
316
    }
324
317
325
    return $self;
318
    return $self;
Lines 327-336 sub revert_transfer { Link Here
327
320
328
=head3 set_waiting
321
=head3 set_waiting
329
322
330
    $recall->set_waiting({
323
    $recall->set_waiting(
331
        expirationdate => $expirationdate,
324
        {   expirationdate => $expirationdate,
332
        item => $item_object
325
            item           => $item_object
333
    });
326
        }
327
    );
334
328
335
Set the recall as waiting and update expiration date.
329
Set the recall as waiting and update expiration date.
336
Notify the recall requester.
330
Notify the recall requester.
Lines 343-353 sub set_waiting { Link Here
343
    my $itemnumber;
337
    my $itemnumber;
344
    if ( $self->item_level_recall ) {
338
    if ( $self->item_level_recall ) {
345
        $itemnumber = $self->itemnumber;
339
        $itemnumber = $self->itemnumber;
346
        $self->update({ status => 'W', waitingdate => dt_from_string, expirationdate => $params->{expirationdate} });
340
        $self->update({ status => 'waiting', waitingdate => dt_from_string, expirationdate => $params->{expirationdate} });
347
    } else {
341
    } else {
348
        # biblio-level recall with no itemnumber. need to set itemnumber
342
        # biblio-level recall with no itemnumber. need to set itemnumber
349
        $itemnumber = $params->{item}->itemnumber;
343
        $itemnumber = $params->{item}->itemnumber;
350
        $self->update({ status => 'W', waitingdate => dt_from_string, expirationdate => $params->{expirationdate}, itemnumber => $itemnumber });
344
        $self->update({ status => 'waiting', waitingdate => dt_from_string, expirationdate => $params->{expirationdate}, itemnumber => $itemnumber });
351
    }
345
    }
352
346
353
    # send notice to recaller to pick up item
347
    # send notice to recaller to pick up item
Lines 380-388 Revert recall waiting status. Link Here
380
sub revert_waiting {
374
sub revert_waiting {
381
    my ( $self ) = @_;
375
    my ( $self ) = @_;
382
    if ( $self->item_level_recall ){
376
    if ( $self->item_level_recall ){
383
        $self->update({ status => 'R', waitingdate => undef });
377
        $self->update({ status => 'requested', waitingdate => undef });
384
    } else {
378
    } else {
385
        $self->update({ status => 'R', waitingdate => undef, itemnumber => undef });
379
        $self->update({ status => 'requested', waitingdate => undef, itemnumber => undef });
386
    }
380
    }
387
    return $self;
381
    return $self;
388
}
382
}
Lines 416-422 Set a recall as overdue when the recall has been requested and the borrower who Link Here
416
sub set_overdue {
410
sub set_overdue {
417
    my ( $self, $params ) = @_;
411
    my ( $self, $params ) = @_;
418
    my $interface = $params->{interface} || 'COMMANDLINE';
412
    my $interface = $params->{interface} || 'COMMANDLINE';
419
    $self->update({ status => 'O' });
413
    $self->update({ status => 'overdue' });
420
    C4::Log::logaction( 'RECALLS', 'OVERDUE', $self->recall_id, "Recall status set to overdue", $interface ) if ( C4::Context->preference('RecallsLog') );
414
    C4::Log::logaction( 'RECALLS', 'OVERDUE', $self->recall_id, "Recall status set to overdue", $interface ) if ( C4::Context->preference('RecallsLog') );
421
    return $self;
415
    return $self;
422
}
416
}
Lines 432-438 Set a recall as expired. This may be done manually or by a cronjob, either when Link Here
432
sub set_expired {
426
sub set_expired {
433
    my ( $self, $params ) = @_;
427
    my ( $self, $params ) = @_;
434
    my $interface = $params->{interface} || 'COMMANDLINE';
428
    my $interface = $params->{interface} || 'COMMANDLINE';
435
    $self->update({ status => 'E', old => 1, expirationdate => dt_from_string });
429
    $self->update({ status => 'expired', old => 1, expirationdate => dt_from_string });
436
    C4::Log::logaction( 'RECALLS', 'EXPIRE', $self->recall_id, "Recall expired", $interface ) if ( C4::Context->preference('RecallsLog') );
430
    C4::Log::logaction( 'RECALLS', 'EXPIRE', $self->recall_id, "Recall expired", $interface ) if ( C4::Context->preference('RecallsLog') );
437
    return $self;
431
    return $self;
438
}
432
}
Lines 447-468 Set a recall as cancelled. This may be done manually, either by the borrower tha Link Here
447
441
448
sub set_cancelled {
442
sub set_cancelled {
449
    my ( $self ) = @_;
443
    my ( $self ) = @_;
450
    $self->update({ status => 'C', old => 1, cancellationdate => dt_from_string });
444
    $self->update({ status => 'cancelled', old => 1, cancellationdate => dt_from_string });
451
    C4::Log::logaction( 'RECALLS', 'CANCEL', $self->recall_id, "Recall cancelled", 'INTRANET' ) if ( C4::Context->preference('RecallsLog') );
445
    C4::Log::logaction( 'RECALLS', 'CANCEL', $self->recall_id, "Recall cancelled", 'INTRANET' ) if ( C4::Context->preference('RecallsLog') );
452
    return $self;
446
    return $self;
453
}
447
}
454
448
455
=head3 set_finished
449
=head3 set_fulfilled
456
450
457
    $recall->set_finished;
451
    $recall->set_fulfilled;
458
452
459
Set a recall as finished. This should only be called when the item allocated to a recall is checked out to the borrower who requested the recall.
453
Set a recall as finished. This should only be called when the item allocated to a recall is checked out to the borrower who requested the recall.
460
454
461
=cut
455
=cut
462
456
463
sub set_finished {
457
sub set_fulfilled {
464
    my ( $self ) = @_;
458
    my ( $self ) = @_;
465
    $self->update({ status => 'F', old => 1 });
459
    $self->update({ status => 'fulfilled', old => 1 });
466
    C4::Log::logaction( 'RECALLS', 'FULFILL', $self->recall_id, "Recall fulfilled", 'INTRANET' ) if ( C4::Context->preference('RecallsLog') );
460
    C4::Log::logaction( 'RECALLS', 'FULFILL', $self->recall_id, "Recall fulfilled", 'INTRANET' ) if ( C4::Context->preference('RecallsLog') );
467
    return $self;
461
    return $self;
468
}
462
}
(-)a/Koha/Recalls.pm (-7 / +17 lines)
Lines 33-41 Koha::Recalls - Koha Recalls Object set class Link Here
33
33
34
=head1 API
34
=head1 API
35
35
36
=head2 Internal methods
36
=head2 Class methods
37
38
=cut
39
37
40
=head3 add_recall
38
=head3 add_recall
41
39
Lines 79-85 sub add_recall { Link Here
79
        recalldate => dt_from_string(),
77
        recalldate => dt_from_string(),
80
        biblionumber => $biblio->biblionumber,
78
        biblionumber => $biblio->biblionumber,
81
        branchcode => $branchcode,
79
        branchcode => $branchcode,
82
        status => 'R',
80
        status => 'requested',
83
        itemnumber => defined $itemnumber ? $itemnumber : undef,
81
        itemnumber => defined $itemnumber ? $itemnumber : undef,
84
        expirationdate => $expirationdate,
82
        expirationdate => $expirationdate,
85
        item_level_recall => defined $itemnumber ? 1 : 0,
83
        item_level_recall => defined $itemnumber ? 1 : 0,
Lines 149-155 sub add_recall { Link Here
149
        borrowernumber => $borrowernumber,
147
        borrowernumber => $borrowernumber,
150
    });
148
    });
151
149
152
A patron is attempting to check out an item that has been recalled by another patron. If the recall is requested/overdue, they have the option of cancelling the recall. If the recall is waiting, they also have the option of reverting the waiting status.
150
A patron is attempting to check out an item that has been recalled by another patron.
151
If the recall is requested/overdue, they have the option of cancelling the recall.
152
If the recall is waiting, they also have the option of reverting the waiting status.
153
153
154
We can also fulfill the recall here if the recall is placed by this borrower.
154
We can also fulfill the recall here if the recall is placed by this borrower.
155
155
Lines 183-191 sub move_recall { Link Here
183
183
184
    if ( $message eq 'no action provided' and $item and $item->biblionumber and $borrowernumber ) {
184
    if ( $message eq 'no action provided' and $item and $item->biblionumber and $borrowernumber ) {
185
        # move_recall was not called to revert or cancel, but was called to fulfill
185
        # move_recall was not called to revert or cancel, but was called to fulfill
186
        my $recall = Koha::Recalls->search({ borrowernumber => $borrowernumber, biblionumber => $item->biblionumber, itemnumber => [ $item->itemnumber, undef ], old => undef }, { order_by => { -asc => 'recalldate' } })->next;
186
        my $recall = Koha::Recalls->search(
187
            {
188
                borrowernumber => $borrowernumber,
189
                biblionumber   => $item->biblionumber,
190
                itemnumber     => [ $item->itemnumber, undef ],
191
                old            => undef
192
            },
193
            { order_by => { -asc => 'recalldate' } }
194
        )->next;
187
        if ( $recall ) {
195
        if ( $recall ) {
188
            $recall->set_finished;
196
            $recall->set_fulfilled;
189
            $message = 'fulfilled';
197
            $message = 'fulfilled';
190
        }
198
        }
191
    }
199
    }
Lines 193-198 sub move_recall { Link Here
193
    return $message;
201
    return $message;
194
}
202
}
195
203
204
=head2 Internal methods
205
196
=head3 _type
206
=head3 _type
197
207
198
=cut
208
=cut
(-)a/Koha/Schema/Result/Borrower.pm (-2 / +2 lines)
Lines 1930-1937 Composing rels: L</user_permissions> -> permission Link Here
1930
__PACKAGE__->many_to_many("permissions", "user_permissions", "permission");
1930
__PACKAGE__->many_to_many("permissions", "user_permissions", "permission");
1931
1931
1932
1932
1933
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-02-25 00:33:23
1933
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-03-11 15:09:09
1934
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:qPGKczsaKaLxxiNzZS5zdQ
1934
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3iAhB3L4DomQBZKohTMSIg
1935
1935
1936
__PACKAGE__->has_many(
1936
__PACKAGE__->has_many(
1937
  "extended_attributes",
1937
  "extended_attributes",
(-)a/Koha/Schema/Result/Branchtransfer.pm (-4 / +9 lines)
Lines 103-115 any comments related to the transfer Link Here
103
=head2 reason
103
=head2 reason
104
104
105
  data_type: 'enum'
105
  data_type: 'enum'
106
  extra: {list => ["Manual","StockrotationAdvance","StockrotationRepatriation","ReturnToHome","ReturnToHolding","RotatingCollection","Reserve","LostReserve","CancelReserve","Recall","CancelRecall"]}
106
  extra: {list => ["Manual","StockrotationAdvance","StockrotationRepatriation","ReturnToHome","ReturnToHolding","RotatingCollection","Reserve","LostReserve","CancelReserve","TransferCancellation","Recall","CancelRecall"]}
107
  is_nullable: 1
107
  is_nullable: 1
108
108
109
what triggered the transfer
110
109
=head2 cancellation_reason
111
=head2 cancellation_reason
110
112
111
  data_type: 'enum'
113
  data_type: 'enum'
112
  extra: {list => ["Manual","StockrotationAdvance","StockrotationRepatriation","ReturnToHome","ReturnToHolding","RotatingCollection","Reserve","LostReserve","CancelReserve","ItemLost","WrongTransfer"]}
114
  extra: {list => ["Manual","StockrotationAdvance","StockrotationRepatriation","ReturnToHome","ReturnToHolding","RotatingCollection","Reserve","LostReserve","CancelReserve","ItemLost","WrongTransfer","Recall","CancelRecall"]}
113
  is_nullable: 1
115
  is_nullable: 1
114
116
115
what triggered the transfer cancellation
117
what triggered the transfer cancellation
Lines 183-188 __PACKAGE__->add_columns( Link Here
183
        "Reserve",
185
        "Reserve",
184
        "LostReserve",
186
        "LostReserve",
185
        "CancelReserve",
187
        "CancelReserve",
188
        "TransferCancellation",
186
        "Recall",
189
        "Recall",
187
        "CancelRecall",
190
        "CancelRecall",
188
      ],
191
      ],
Lines 205-210 __PACKAGE__->add_columns( Link Here
205
        "CancelReserve",
208
        "CancelReserve",
206
        "ItemLost",
209
        "ItemLost",
207
        "WrongTransfer",
210
        "WrongTransfer",
211
        "Recall",
212
        "CancelRecall",
208
      ],
213
      ],
209
    },
214
    },
210
    is_nullable => 1,
215
    is_nullable => 1,
Lines 271-278 __PACKAGE__->belongs_to( Link Here
271
);
276
);
272
277
273
278
274
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2021-10-14 15:07:03
279
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-03-11 15:09:09
275
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:APOPxPO4uRpPHgSEhXbnTw
280
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:fBpQLcKUzN3siNGU6EYFZA
276
281
277
sub koha_object_class {
282
sub koha_object_class {
278
    'Koha::Item::Transfer';
283
    'Koha::Item::Transfer';
(-)a/Koha/Schema/Result/Recall.pm (-6 / +25 lines)
Lines 74-82 __PACKAGE__->table("recalls"); Link Here
74
74
75
=head2 status
75
=head2 status
76
76
77
  data_type: 'varchar'
77
  data_type: 'enum'
78
  default_value: 'requested'
79
  extra: {list => ["requested","overdue","waiting","in_transit","cancelled","expired","fulfilled"]}
78
  is_nullable: 1
80
  is_nullable: 1
79
  size: 1
81
82
Request status
80
83
81
=head2 timestamp
84
=head2 timestamp
82
85
Lines 106-111 __PACKAGE__->table("recalls"); Link Here
106
=head2 old
109
=head2 old
107
110
108
  data_type: 'tinyint'
111
  data_type: 'tinyint'
112
  default_value: 0
109
  is_nullable: 1
113
  is_nullable: 1
110
114
111
=head2 item_level_recall
115
=head2 item_level_recall
Lines 152-158 __PACKAGE__->add_columns( Link Here
152
  "priority",
156
  "priority",
153
  { data_type => "smallint", is_nullable => 1 },
157
  { data_type => "smallint", is_nullable => 1 },
154
  "status",
158
  "status",
155
  { data_type => "varchar", is_nullable => 1, size => 1 },
159
  {
160
    data_type => "enum",
161
    default_value => "requested",
162
    extra => {
163
      list => [
164
        "requested",
165
        "overdue",
166
        "waiting",
167
        "in_transit",
168
        "cancelled",
169
        "expired",
170
        "fulfilled",
171
      ],
172
    },
173
    is_nullable => 1,
174
  },
156
  "timestamp",
175
  "timestamp",
157
  {
176
  {
158
    data_type => "timestamp",
177
    data_type => "timestamp",
Lines 175-181 __PACKAGE__->add_columns( Link Here
175
    is_nullable => 1,
194
    is_nullable => 1,
176
  },
195
  },
177
  "old",
196
  "old",
178
  { data_type => "tinyint", is_nullable => 1 },
197
  { data_type => "tinyint", default_value => 0, is_nullable => 1 },
179
  "item_level_recall",
198
  "item_level_recall",
180
  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
199
  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
181
);
200
);
Lines 265-272 __PACKAGE__->belongs_to( Link Here
265
);
284
);
266
285
267
286
268
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2021-10-14 15:07:03
287
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-03-11 15:09:09
269
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3OJBkRJzqxZpuRp0GYGixw
288
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0O1XsinX9DtgTZz+lDNd7g
270
289
271
__PACKAGE__->add_columns(
290
__PACKAGE__->add_columns(
272
    '+old' => { is_boolean => 1 },
291
    '+old' => { is_boolean => 1 },
(-)a/installer/data/mysql/atomicupdate/bug_19532_make_status_enum.pl (+16 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number => "19532",
5
    description => "Make recalls.status an enum",
6
    up => sub {
7
        my ($args) = @_;
8
        my ($dbh) = @$args{qw(dbh)};
9
10
        $dbh->do(q{
11
            ALTER TABLE recalls
12
            MODIFY COLUMN
13
                status ENUM('requested','overdue','waiting','in_transit','cancelled','expired','fulfilled') DEFAULT 'requested' COMMENT "Request status"
14
        });
15
    },
16
};
(-)a/installer/data/mysql/kohastructure.sql (-2 / +2 lines)
Lines 4291-4302 CREATE TABLE recalls ( -- information related to recalls in Koha Link Here
4291
    cancellationdate datetime DEFAULT NULL, -- the date this recall was cancelled
4291
    cancellationdate datetime DEFAULT NULL, -- the date this recall was cancelled
4292
    recallnotes mediumtext, -- notes related to this recall
4292
    recallnotes mediumtext, -- notes related to this recall
4293
    priority smallint(6) DEFAULT NULL, -- where in the queue the patron sits
4293
    priority smallint(6) DEFAULT NULL, -- where in the queue the patron sits
4294
    status varchar(1) DEFAULT NULL, -- a one letter code defining the status of the recall. R=requested, O=overdue, W=awaiting pickup, T=in transit, E=expired, C=cancelled, F=finished/completed
4294
    status ENUM('requested','overdue','waiting','in_transit','cancelled','expired','fulfilled') DEFAULT 'requested' COMMENT "Request status",
4295
    timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- the date and time this recall was last updated
4295
    timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- the date and time this recall was last updated
4296
    itemnumber int(11) DEFAULT NULL, -- foreign key from the items table defining the specific item the recall request was placed on
4296
    itemnumber int(11) DEFAULT NULL, -- foreign key from the items table defining the specific item the recall request was placed on
4297
    waitingdate datetime DEFAULT NULL, -- the date the item was marked as waiting for the patron at the library
4297
    waitingdate datetime DEFAULT NULL, -- the date the item was marked as waiting for the patron at the library
4298
    expirationdate datetime DEFAULT NULL, -- the date the recall expires
4298
    expirationdate datetime DEFAULT NULL, -- the date the recall expires
4299
    old TINYINT(1) DEFAULT NULL, -- flag if the recall is old and no longer active, i.e. expired, cancelled or completed
4299
    old TINYINT(1) DEFAULT 0, -- flag if the recall is old and no longer active, i.e. expired, cancelled or completed
4300
    item_level_recall TINYINT(1) NOT NULL DEFAULT 0, -- flag if item-level recall
4300
    item_level_recall TINYINT(1) NOT NULL DEFAULT 0, -- flag if item-level recall
4301
     PRIMARY KEY (recall_id),
4301
     PRIMARY KEY (recall_id),
4302
     KEY borrowernumber (borrowernumber),
4302
     KEY borrowernumber (borrowernumber),
(-)a/misc/devel/update_dbix_class_files.pl (-1 / +1 lines)
Lines 38-44 my $db_name; Link Here
38
my $db_user;
38
my $db_user;
39
my $db_passwd;
39
my $db_passwd;
40
my $koha_conf;
40
my $koha_conf;
41
my $force;
41
my $force = 1;
42
my $help;
42
my $help;
43
43
44
GetOptions(
44
GetOptions(
(-)a/t/db_dependent/Circulation.t (-78 / +74 lines)
Lines 1455-1461 subtest "CanBookBeRenewed tests" => sub { Link Here
1455
        borrowernumber => $recall_borrower->borrowernumber,
1455
        borrowernumber => $recall_borrower->borrowernumber,
1456
        branchcode => $recall_borrower->branchcode,
1456
        branchcode => $recall_borrower->branchcode,
1457
        item_level_recall => 1,
1457
        item_level_recall => 1,
1458
        status => 'R',
1459
    })->store;
1458
    })->store;
1460
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1459
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1461
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1460
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
Lines 1468-1474 subtest "CanBookBeRenewed tests" => sub { Link Here
1468
        borrowernumber => $recall_borrower->borrowernumber,
1467
        borrowernumber => $recall_borrower->borrowernumber,
1469
        branchcode => $recall_borrower->branchcode,
1468
        branchcode => $recall_borrower->branchcode,
1470
        item_level_recall => 0,
1469
        item_level_recall => 0,
1471
        status => 'R',
1472
    })->store;
1470
    })->store;
1473
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1471
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1474
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1472
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
Lines 1481-1487 subtest "CanBookBeRenewed tests" => sub { Link Here
1481
        borrowernumber => $recall_borrower->borrowernumber,
1479
        borrowernumber => $recall_borrower->borrowernumber,
1482
        branchcode => $recall_borrower->branchcode,
1480
        branchcode => $recall_borrower->branchcode,
1483
        item_level_recall => 1,
1481
        item_level_recall => 1,
1484
        status => 'R',
1485
    })->store;
1482
    })->store;
1486
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1483
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1487
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1484
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
Lines 1494-1500 subtest "CanBookBeRenewed tests" => sub { Link Here
1494
        borrowernumber => $recall_borrower->borrowernumber,
1491
        borrowernumber => $recall_borrower->borrowernumber,
1495
        branchcode => $recall_borrower->branchcode,
1492
        branchcode => $recall_borrower->branchcode,
1496
        item_level_recall => 0,
1493
        item_level_recall => 0,
1497
        status => 'R',
1498
    })->store;
1494
    })->store;
1499
    $recall->set_waiting({ item => $recall_item1 });
1495
    $recall->set_waiting({ item => $recall_item1 });
1500
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1496
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
Lines 1998-2039 subtest 'AddIssue | recalls' => sub { Link Here
1998
    });
1994
    });
1999
1995
2000
    # checking out item that they have recalled
1996
    # checking out item that they have recalled
2001
    my $recall1 = Koha::Recall->new({
1997
    my $recall1 = Koha::Recall->new(
2002
        borrowernumber => $patron1->borrowernumber,
1998
        {   borrowernumber    => $patron1->borrowernumber,
2003
        biblionumber => $item->biblionumber,
1999
            biblionumber      => $item->biblionumber,
2004
        itemnumber => $item->itemnumber,
2000
            itemnumber        => $item->itemnumber,
2005
        item_level_recall => 1,
2001
            item_level_recall => 1,
2006
        branchcode => $patron1->branchcode,
2002
            branchcode        => $patron1->branchcode,
2007
        status => 'R',
2003
        }
2008
    })->store;
2004
    )->store;
2009
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall1->recall_id } );
2005
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall1->recall_id } );
2010
    $recall1 = Koha::Recalls->find( $recall1->recall_id );
2006
    $recall1 = Koha::Recalls->find( $recall1->recall_id );
2011
    is( $recall1->finished, 1, 'Recall was fulfilled when patron checked out item' );
2007
    is( $recall1->fulfilled, 1, 'Recall was fulfilled when patron checked out item' );
2012
    AddReturn( $item->barcode, $item->homebranch );
2008
    AddReturn( $item->barcode, $item->homebranch );
2013
2009
2014
    # this item is has a recall request. cancel recall
2010
    # this item is has a recall request. cancel recall
2015
    my $recall2 = Koha::Recall->new({
2011
    my $recall2 = Koha::Recall->new(
2016
        borrowernumber => $patron2->borrowernumber,
2012
        {   borrowernumber    => $patron2->borrowernumber,
2017
        biblionumber => $item->biblionumber,
2013
            biblionumber      => $item->biblionumber,
2018
        itemnumber => $item->itemnumber,
2014
            itemnumber        => $item->itemnumber,
2019
        item_level_recall => 1,
2015
            item_level_recall => 1,
2020
        branchcode => $patron2->branchcode,
2016
            branchcode        => $patron2->branchcode,
2021
        status => 'R',
2017
        }
2022
    })->store;
2018
    )->store;
2023
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall2->recall_id, cancel_recall => 'cancel' } );
2019
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall2->recall_id, cancel_recall => 'cancel' } );
2024
    $recall2 = Koha::Recalls->find( $recall2->recall_id );
2020
    $recall2 = Koha::Recalls->find( $recall2->recall_id );
2025
    is( $recall2->cancelled, 1, 'Recall was cancelled when patron checked out item' );
2021
    is( $recall2->cancelled, 1, 'Recall was cancelled when patron checked out item' );
2026
    AddReturn( $item->barcode, $item->homebranch );
2022
    AddReturn( $item->barcode, $item->homebranch );
2027
2023
2028
    # this item is waiting to fulfill a recall. revert recall
2024
    # this item is waiting to fulfill a recall. revert recall
2029
    my $recall3 = Koha::Recall->new({
2025
    my $recall3 = Koha::Recall->new(
2030
        borrowernumber => $patron2->borrowernumber,
2026
        {   borrowernumber    => $patron2->borrowernumber,
2031
        biblionumber => $item->biblionumber,
2027
            biblionumber      => $item->biblionumber,
2032
        itemnumber => $item->itemnumber,
2028
            itemnumber        => $item->itemnumber,
2033
        item_level_recall => 1,
2029
            item_level_recall => 1,
2034
        branchcode => $patron2->branchcode,
2030
            branchcode        => $patron2->branchcode,
2035
        status => 'R',
2031
        }
2036
    })->store;
2032
    )->store;
2037
    $recall3->set_waiting;
2033
    $recall3->set_waiting;
2038
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall3->recall_id, cancel_recall => 'revert' } );
2034
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall3->recall_id, cancel_recall => 'revert' } );
2039
    $recall3 = Koha::Recalls->find( $recall3->recall_id );
2035
    $recall3 = Koha::Recalls->find( $recall3->recall_id );
Lines 3978-3991 subtest 'CanBookBeIssued | recalls' => sub { Link Here
3978
    });
3974
    });
3979
3975
3980
    # item-level recall
3976
    # item-level recall
3981
    my $recall = Koha::Recall->new({
3977
    my $recall = Koha::Recall->new(
3982
        borrowernumber => $patron1->borrowernumber,
3978
        {   borrowernumber    => $patron1->borrowernumber,
3983
        biblionumber => $item->biblionumber,
3979
            biblionumber      => $item->biblionumber,
3984
        itemnumber => $item->itemnumber,
3980
            itemnumber        => $item->itemnumber,
3985
        item_level_recall => 1,
3981
            item_level_recall => 1,
3986
        branchcode => $patron1->branchcode,
3982
            branchcode        => $patron1->branchcode,
3987
        status => 'R',
3983
        }
3988
    })->store;
3984
    )->store;
3989
3985
3990
    my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
3986
    my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
3991
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed an item-level recall on this item" );
3987
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed an item-level recall on this item" );
Lines 3993-4006 subtest 'CanBookBeIssued | recalls' => sub { Link Here
3993
    $recall->set_cancelled;
3989
    $recall->set_cancelled;
3994
3990
3995
    # biblio-level recall
3991
    # biblio-level recall
3996
    $recall = Koha::Recall->new({
3992
    $recall = Koha::Recall->new(
3997
        borrowernumber => $patron1->borrowernumber,
3993
        {   borrowernumber    => $patron1->borrowernumber,
3998
        biblionumber => $item->biblionumber,
3994
            biblionumber      => $item->biblionumber,
3999
        itemnumber => undef,
3995
            itemnumber        => undef,
4000
        item_level_recall => 0,
3996
            item_level_recall => 0,
4001
        branchcode => $patron1->branchcode,
3997
            branchcode        => $patron1->branchcode,
4002
        status => 'R',
3998
        }
4003
    })->store;
3999
    )->store;
4004
4000
4005
    ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
4001
    ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
4006
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed a biblio-level recall and this item is eligible to fill it" );
4002
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed a biblio-level recall and this item is eligible to fill it" );
Lines 4008-4022 subtest 'CanBookBeIssued | recalls' => sub { Link Here
4008
    $recall->set_cancelled;
4004
    $recall->set_cancelled;
4009
4005
4010
    # biblio-level recall
4006
    # biblio-level recall
4011
    $recall = Koha::Recall->new({
4007
    $recall = Koha::Recall->new(
4012
        borrowernumber => $patron1->borrowernumber,
4008
        {   borrowernumber    => $patron1->borrowernumber,
4013
        biblionumber => $item->biblionumber,
4009
            biblionumber      => $item->biblionumber,
4014
        itemnumber => undef,
4010
            itemnumber        => undef,
4015
        item_level_recall => 0,
4011
            item_level_recall => 0,
4016
        branchcode => $patron1->branchcode,
4012
            branchcode        => $patron1->branchcode,
4017
        status => 'R',
4013
        }
4018
    })->store;
4014
    )->store;
4019
    $recall->set_waiting({ item => $item, expirationdate => dt_from_string() });
4015
    $recall->set_waiting( { item => $item, expirationdate => dt_from_string() } );
4020
4016
4021
    my ( undef, undef, undef, $messages ) = CanBookBeIssued( $patron1, $item->barcode, undef, undef, undef, undef );
4017
    my ( undef, undef, undef, $messages ) = CanBookBeIssued( $patron1, $item->barcode, undef, undef, undef, undef );
4022
    is( $messages->{RECALLED}, $recall->recall_id, "This book can be issued by this patron and they have placed a recall" );
4018
    is( $messages->{RECALLED}, $recall->recall_id, "This book can be issued by this patron and they have placed a recall" );
Lines 4058-4099 subtest 'AddReturn | recalls' => sub { Link Here
4058
4054
4059
    # this item can fill a recall with pickup at this branch
4055
    # this item can fill a recall with pickup at this branch
4060
    AddIssue( $patron1->unblessed, $item1->barcode );
4056
    AddIssue( $patron1->unblessed, $item1->barcode );
4061
    my $recall1 = Koha::Recall->new({
4057
    my $recall1 = Koha::Recall->new(
4062
        borrowernumber => $patron2->borrowernumber,
4058
        {   borrowernumber    => $patron2->borrowernumber,
4063
        biblionumber => $item1->biblionumber,
4059
            biblionumber      => $item1->biblionumber,
4064
        itemnumber => $item1->itemnumber,
4060
            itemnumber        => $item1->itemnumber,
4065
        item_level_recall => 1,
4061
            item_level_recall => 1,
4066
        branchcode => $item1->homebranch,
4062
            branchcode        => $item1->homebranch,
4067
        status => 'R',
4063
        }
4068
    })->store;
4064
    )->store;
4069
    my ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
4065
    my ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
4070
    is( $messages->{RecallFound}->recall_id, $recall1->recall_id, "Recall found" );
4066
    is( $messages->{RecallFound}->recall_id, $recall1->recall_id, "Recall found" );
4071
    $recall1->set_cancelled;
4067
    $recall1->set_cancelled;
4072
4068
4073
    # this item can fill a recall but needs transfer
4069
    # this item can fill a recall but needs transfer
4074
    AddIssue( $patron1->unblessed, $item1->barcode );
4070
    AddIssue( $patron1->unblessed, $item1->barcode );
4075
    $recall1 = Koha::Recall->new({
4071
    $recall1 = Koha::Recall->new(
4076
        borrowernumber => $patron2->borrowernumber,
4072
        {   borrowernumber    => $patron2->borrowernumber,
4077
        biblionumber => $item1->biblionumber,
4073
            biblionumber      => $item1->biblionumber,
4078
        itemnumber => $item1->itemnumber,
4074
            itemnumber        => $item1->itemnumber,
4079
        item_level_recall => 1,
4075
            item_level_recall => 1,
4080
        branchcode => $patron2->branchcode,
4076
            branchcode        => $patron2->branchcode,
4081
        status => 'R',
4077
        }
4082
    })->store;
4078
    )->store;
4083
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
4079
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
4084
    is( $messages->{RecallNeedsTransfer}, $item1->homebranch, "Recall requiring transfer found" );
4080
    is( $messages->{RecallNeedsTransfer}, $item1->homebranch, "Recall requiring transfer found" );
4085
    $recall1->set_cancelled;
4081
    $recall1->set_cancelled;
4086
4082
4087
    # this item is already in transit, do not ask to transfer
4083
    # this item is already in transit, do not ask to transfer
4088
    AddIssue( $patron1->unblessed, $item1->barcode );
4084
    AddIssue( $patron1->unblessed, $item1->barcode );
4089
    $recall1 = Koha::Recall->new({
4085
    $recall1 = Koha::Recall->new(
4090
        borrowernumber => $patron2->borrowernumber,
4086
        {   borrowernumber    => $patron2->borrowernumber,
4091
        biblionumber => $item1->biblionumber,
4087
            biblionumber      => $item1->biblionumber,
4092
        itemnumber => $item1->itemnumber,
4088
            itemnumber        => $item1->itemnumber,
4093
        item_level_recall => 1,
4089
            item_level_recall => 1,
4094
        branchcode => $patron2->branchcode,
4090
            branchcode        => $patron2->branchcode,
4095
        status => 'R',
4091
        }
4096
    })->store;
4092
    )->store;
4097
    $recall1->start_transfer;
4093
    $recall1->start_transfer;
4098
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $patron2->branchcode );
4094
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $patron2->branchcode );
4099
    is( $messages->{TransferredRecall}->recall_id, $recall1->recall_id, "In transit recall found" );
4095
    is( $messages->{TransferredRecall}->recall_id, $recall1->recall_id, "In transit recall found" );
(-)a/t/db_dependent/Circulation/CalcFine.t (-2 / +1 lines)
Lines 232-238 subtest 'Recall overdue fines' => sub { Link Here
232
        recalldate => dt_from_string,
232
        recalldate => dt_from_string,
233
        biblionumber => $item->biblionumber,
233
        biblionumber => $item->biblionumber,
234
        branchcode => $branch->{branchcode},
234
        branchcode => $branch->{branchcode},
235
        status => 'R',
236
        itemnumber => $item->itemnumber,
235
        itemnumber => $item->itemnumber,
237
        expirationdate => undef,
236
        expirationdate => undef,
238
        item_level_recall => 1
237
        item_level_recall => 1
Lines 242-248 subtest 'Recall overdue fines' => sub { Link Here
242
    my ($amount) = CalcFine( $item->unblessed, $patron->{categorycode}, $branch->{branchcode}, $start_dt, $end_dt );
241
    my ($amount) = CalcFine( $item->unblessed, $patron->{categorycode}, $branch->{branchcode}, $start_dt, $end_dt );
243
    is( int($amount), 25, 'Use recall fine amount specified in circulation rules' );
242
    is( int($amount), 25, 'Use recall fine amount specified in circulation rules' );
244
243
245
    $recall->set_finished;
244
    $recall->set_fulfilled;
246
    ($amount) = CalcFine( $item->unblessed, $patron->{categorycode}, $branch->{branchcode}, $start_dt, $end_dt );
245
    ($amount) = CalcFine( $item->unblessed, $patron->{categorycode}, $branch->{branchcode}, $start_dt, $end_dt );
247
    is( int($amount), 5, 'With no recall, use normal fine amount' );
246
    is( int($amount), 5, 'With no recall, use normal fine amount' );
248
247
(-)a/t/db_dependent/Circulation/transferbook.t (-16 / +16 lines)
Lines 157-183 subtest 'transfer already at destination' => sub { Link Here
157
157
158
    # recalls
158
    # recalls
159
    t::lib::Mocks::mock_preference('UseRecalls', 1);
159
    t::lib::Mocks::mock_preference('UseRecalls', 1);
160
    my $recall = Koha::Recall->new({
160
    my $recall = Koha::Recall->new(
161
        biblionumber => $item->biblionumber,
161
        {   biblionumber      => $item->biblionumber,
162
        itemnumber => $item->itemnumber,
162
            itemnumber        => $item->itemnumber,
163
        item_level_recall => 1,
163
            item_level_recall => 1,
164
        borrowernumber => $patron->borrowernumber,
164
            borrowernumber    => $patron->borrowernumber,
165
        branchcode => $library->branchcode,
165
            branchcode        => $library->branchcode,
166
        status => 'R',
166
        }
167
    })->store;
167
    )->store;
168
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
168
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
169
    is( $dotransfer, 0, 'Do not transfer recalled item, it has already arrived' );
169
    is( $dotransfer, 0, 'Do not transfer recalled item, it has already arrived' );
170
    is( $messages->{RecallPlacedAtHoldingBranch}, 1, "We found the recall");
170
    is( $messages->{RecallPlacedAtHoldingBranch}, 1, "We found the recall");
171
171
172
    my $item2 = $builder->build_object({ class => 'Koha::Items' }); # this item will have a different holding branch to the pickup branch
172
    my $item2 = $builder->build_object({ class => 'Koha::Items' }); # this item will have a different holding branch to the pickup branch
173
    $recall = Koha::Recall->new({
173
    $recall = Koha::Recall->new(
174
        biblionumber => $item2->biblionumber,
174
        {   biblionumber      => $item2->biblionumber,
175
        itemnumber => $item2->itemnumber,
175
            itemnumber        => $item2->itemnumber,
176
        item_level_recall => 1,
176
            item_level_recall => 1,
177
        borrowernumber => $patron->borrowernumber,
177
            borrowernumber    => $patron->borrowernumber,
178
        branchcode => $library->branchcode,
178
            branchcode        => $library->branchcode,
179
        status => 'R',
179
        }
180
    })->store;
180
    )->store;
181
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
181
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
182
    is( $dotransfer, 1, 'Transfer of recalled item succeeded' );
182
    is( $dotransfer, 1, 'Transfer of recalled item succeeded' );
183
    is( $messages->{RecallFound}->recall_id, $recall->recall_id, "We found the recall");
183
    is( $messages->{RecallFound}->recall_id, $recall->recall_id, "We found the recall");
(-)a/t/db_dependent/Koha/Biblio.t (-30 / +31 lines)
Lines 888-893 subtest 'Recalls tests' => sub { Link Here
888
    plan tests => 12;
888
    plan tests => 12;
889
889
890
    $schema->storage->txn_begin;
890
    $schema->storage->txn_begin;
891
891
    my $item1 = $builder->build_sample_item;
892
    my $item1 = $builder->build_sample_item;
892
    my $biblio = $item1->biblio;
893
    my $biblio = $item1->biblio;
893
    my $branchcode = $item1->holdingbranch;
894
    my $branchcode = $item1->holdingbranch;
Lines 897-932 subtest 'Recalls tests' => sub { Link Here
897
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype } });
898
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype } });
898
    t::lib::Mocks::mock_userenv({ patron => $patron1 });
899
    t::lib::Mocks::mock_userenv({ patron => $patron1 });
899
900
900
    my $recall1 = Koha::Recall->new({
901
    my $recall1 = Koha::Recall->new(
901
        borrowernumber => $patron1->borrowernumber,
902
        {   borrowernumber    => $patron1->borrowernumber,
902
        recalldate => Koha::DateUtils::dt_from_string,
903
            recalldate        => \'NOW()',
903
        biblionumber => $biblio->biblionumber,
904
            biblionumber      => $biblio->biblionumber,
904
        branchcode => $branchcode,
905
            branchcode        => $branchcode,
905
        status => 'R',
906
            itemnumber        => $item1->itemnumber,
906
        itemnumber => $item1->itemnumber,
907
            expirationdate    => undef,
907
        expirationdate => undef,
908
            item_level_recall => 1
908
        item_level_recall => 1
909
        }
909
    })->store;
910
    )->store;
910
    my $recall2 = Koha::Recall->new({
911
    my $recall2 = Koha::Recall->new(
911
        borrowernumber => $patron2->borrowernumber,
912
        {   borrowernumber    => $patron2->borrowernumber,
912
        recalldate => Koha::DateUtils::dt_from_string,
913
            recalldate        => \'NOW()',
913
        biblionumber => $biblio->biblionumber,
914
            biblionumber      => $biblio->biblionumber,
914
        branchcode => $branchcode,
915
            branchcode        => $branchcode,
915
        status => 'R',
916
            itemnumber        => undef,
916
        itemnumber => undef,
917
            expirationdate    => undef,
917
        expirationdate => undef,
918
            item_level_recall => 0
918
        item_level_recall => 0
919
        }
919
    })->store;
920
    )->store;
920
    my $recall3 = Koha::Recall->new({
921
    my $recall3 = Koha::Recall->new(
921
        borrowernumber => $patron3->borrowernumber,
922
        {   borrowernumber    => $patron3->borrowernumber,
922
        recalldate => Koha::DateUtils::dt_from_string,
923
            recalldate        => \'NOW()',
923
        biblionumber => $biblio->biblionumber,
924
            biblionumber      => $biblio->biblionumber,
924
        branchcode => $branchcode,
925
            branchcode        => $branchcode,
925
        status => 'R',
926
            itemnumber        => $item1->itemnumber,
926
        itemnumber => $item1->itemnumber,
927
            expirationdate    => undef,
927
        expirationdate => undef,
928
            item_level_recall => 1
928
        item_level_recall => 1
929
        }
929
    })->store;
930
    )->store;
930
931
931
    my $recalls_count = $biblio->recalls->count;
932
    my $recalls_count = $biblio->recalls->count;
932
    is( $recalls_count, 3, 'Correctly get number of active recalls for biblio' );
933
    is( $recalls_count, 3, 'Correctly get number of active recalls for biblio' );
(-)a/t/db_dependent/Koha/Item.t (-53 / +58 lines)
Lines 1179-1207 subtest 'Recalls tests' => sub { Link Here
1179
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1179
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1180
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1180
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1181
    my $patron3 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1181
    my $patron3 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
1182
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype } });
1182
    my $item2 = $builder->build_object(
1183
    t::lib::Mocks::mock_userenv({ patron => $patron1 });
1183
        {   class => 'Koha::Items',
1184
            value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype }
1185
        }
1186
    );
1184
1187
1185
    my $recall1 = Koha::Recall->new({
1188
    t::lib::Mocks::mock_userenv( { patron => $patron1 } );
1186
        borrowernumber => $patron1->borrowernumber,
1189
1187
        recalldate => Koha::DateUtils::dt_from_string,
1190
    my $recall1 = Koha::Recall->new(
1188
        biblionumber => $biblio->biblionumber,
1191
        {   borrowernumber    => $patron1->borrowernumber,
1189
        branchcode => $branchcode,
1192
            recalldate        => \'NOW()',
1190
        status => 'R',
1193
            biblionumber      => $biblio->biblionumber,
1191
        itemnumber => $item1->itemnumber,
1194
            branchcode        => $branchcode,
1192
        expirationdate => undef,
1195
            itemnumber        => $item1->itemnumber,
1193
        item_level_recall => 1
1196
            expirationdate    => undef,
1194
    })->store;
1197
            item_level_recall => 1
1195
    my $recall2 = Koha::Recall->new({
1198
        }
1196
        borrowernumber => $patron2->borrowernumber,
1199
    )->store;
1197
        recalldate => Koha::DateUtils::dt_from_string,
1200
    my $recall2 = Koha::Recall->new(
1198
        biblionumber => $biblio->biblionumber,
1201
        {   borrowernumber    => $patron2->borrowernumber,
1199
        branchcode => $branchcode,
1202
            recalldate        => \'NOW()',
1200
        status => 'R',
1203
            biblionumber      => $biblio->biblionumber,
1201
        itemnumber => $item1->itemnumber,
1204
            branchcode        => $branchcode,
1202
        expirationdate => undef,
1205
            itemnumber        => $item1->itemnumber,
1203
        item_level_recall =>1
1206
            expirationdate    => undef,
1204
    })->store;
1207
            item_level_recall => 1
1208
        }
1209
    )->store;
1205
1210
1206
    is( $item1->recall->borrowernumber, $patron1->borrowernumber, 'Correctly returns most relevant recall' );
1211
    is( $item1->recall->borrowernumber, $patron1->borrowernumber, 'Correctly returns most relevant recall' );
1207
1212
Lines 1274-1289 subtest 'Recalls tests' => sub { Link Here
1274
    C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
1279
    C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
1275
    is( $item1->can_be_recalled({ patron => $patron1 }), 1, "Can recall item" );
1280
    is( $item1->can_be_recalled({ patron => $patron1 }), 1, "Can recall item" );
1276
1281
1277
    $recall1 = Koha::Recall->new({
1282
    $recall1 = Koha::Recall->new(
1278
        borrowernumber => $patron1->borrowernumber,
1283
        {   borrowernumber    => $patron1->borrowernumber,
1279
        recalldate => Koha::DateUtils::dt_from_string,
1284
            recalldate        => \'NOW()',
1280
        biblionumber => $biblio->biblionumber,
1285
            biblionumber      => $biblio->biblionumber,
1281
        branchcode => $branchcode,
1286
            branchcode        => $branchcode,
1282
        status => 'R',
1287
            itemnumber        => undef,
1283
        itemnumber => undef,
1288
            expirationdate    => undef,
1284
        expirationdate => undef,
1289
            item_level_recall => 0
1285
        item_level_recall => 0
1290
        }
1286
    })->store;
1291
    )->store;
1287
1292
1288
    # Patron2 has Item1 checked out. Patron1 has placed a biblio-level recall on Biblio1, so check if Item1 can fulfill Patron1's recall.
1293
    # Patron2 has Item1 checked out. Patron1 has placed a biblio-level recall on Biblio1, so check if Item1 can fulfill Patron1's recall.
1289
1294
Lines 1313-1339 subtest 'Recalls tests' => sub { Link Here
1313
1318
1314
    # check_recalls tests
1319
    # check_recalls tests
1315
1320
1316
    $recall1 = Koha::Recall->new({
1321
    $recall1 = Koha::Recall->new(
1317
        borrowernumber => $patron2->borrowernumber,
1322
        {   borrowernumber    => $patron2->borrowernumber,
1318
        recalldate => Koha::DateUtils::dt_from_string,
1323
            recalldate        => \'NOW()',
1319
        biblionumber => $biblio->biblionumber,
1324
            biblionumber      => $biblio->biblionumber,
1320
        branchcode => $branchcode,
1325
            branchcode        => $branchcode,
1321
        status => 'R',
1326
            itemnumber        => $item1->itemnumber,
1322
        itemnumber => $item1->itemnumber,
1327
            expirationdate    => undef,
1323
        expirationdate => undef,
1328
            item_level_recall => 1
1324
        item_level_recall => 1
1329
        }
1325
    })->store;
1330
    )->store;
1326
    $recall2 = Koha::Recall->new({
1331
    $recall2 = Koha::Recall->new(
1327
        borrowernumber => $patron1->borrowernumber,
1332
        {   borrowernumber    => $patron1->borrowernumber,
1328
        recalldate => Koha::DateUtils::dt_from_string,
1333
            recalldate        => \'NOW()',
1329
        biblionumber => $biblio->biblionumber,
1334
            biblionumber      => $biblio->biblionumber,
1330
        branchcode => $branchcode,
1335
            branchcode        => $branchcode,
1331
        status => 'R',
1336
            itemnumber        => undef,
1332
        itemnumber => undef,
1337
            expirationdate    => undef,
1333
        expirationdate => undef,
1338
            item_level_recall => 0
1334
        item_level_recall => 0
1339
        }
1335
    })->store;
1340
    )->store;
1336
    $recall2->set_waiting({ item => $item1 });
1341
    $recall2->set_waiting( { item => $item1 } );
1337
1342
1338
    # return a waiting recall
1343
    # return a waiting recall
1339
    my $check_recall = $item1->check_recalls;
1344
    my $check_recall = $item1->check_recalls;
(-)a/t/db_dependent/Koha/Patron.t (-36 / +36 lines)
Lines 1060-1101 subtest 'recalls() tests' => sub { Link Here
1060
    my $biblio2 = $builder->build_object({ class => 'Koha::Biblios' });
1060
    my $biblio2 = $builder->build_object({ class => 'Koha::Biblios' });
1061
    my $item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio2->biblionumber } });
1061
    my $item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio2->biblionumber } });
1062
1062
1063
    Koha::Recall->new({
1063
    Koha::Recall->new(
1064
        biblionumber => $biblio1->biblionumber,
1064
        {   biblionumber      => $biblio1->biblionumber,
1065
        borrowernumber => $patron->borrowernumber,
1065
            borrowernumber    => $patron->borrowernumber,
1066
        itemnumber => $item1->itemnumber,
1066
            itemnumber        => $item1->itemnumber,
1067
        branchcode => $patron->branchcode,
1067
            branchcode        => $patron->branchcode,
1068
        recalldate => dt_from_string,
1068
            recalldate        => \'NOW()',
1069
        status => 'R',
1069
            item_level_recall => 1,
1070
        item_level_recall => 1,
1070
        }
1071
    })->store;
1071
    )->store;
1072
    Koha::Recall->new({
1072
    Koha::Recall->new(
1073
        biblionumber => $biblio2->biblionumber,
1073
        {   biblionumber      => $biblio2->biblionumber,
1074
        borrowernumber => $patron->borrowernumber,
1074
            borrowernumber    => $patron->borrowernumber,
1075
        itemnumber => $item2->itemnumber,
1075
            itemnumber        => $item2->itemnumber,
1076
        branchcode => $patron->branchcode,
1076
            branchcode        => $patron->branchcode,
1077
        recalldate => dt_from_string,
1077
            recalldate        => \'NOW()',
1078
        status => 'R',
1078
            item_level_recall => 1,
1079
        item_level_recall => 1,
1079
        }
1080
    })->store;
1080
    )->store;
1081
    Koha::Recall->new({
1081
    Koha::Recall->new(
1082
        biblionumber => $biblio1->biblionumber,
1082
        {   biblionumber      => $biblio1->biblionumber,
1083
        borrowernumber => $patron->borrowernumber,
1083
            borrowernumber    => $patron->borrowernumber,
1084
        itemnumber => undef,
1084
            itemnumber        => undef,
1085
        branchcode => $patron->branchcode,
1085
            branchcode        => $patron->branchcode,
1086
        recalldate => dt_from_string,
1086
            recalldate        => \'NOW()',
1087
        status => 'R',
1087
            item_level_recall => 0,
1088
        item_level_recall => 0,
1088
        }
1089
    })->store;
1089
    )->store;
1090
    my $recall = Koha::Recall->new({
1090
    my $recall = Koha::Recall->new(
1091
        biblionumber => $biblio1->biblionumber,
1091
        {   biblionumber      => $biblio1->biblionumber,
1092
        borrowernumber => $patron->borrowernumber,
1092
            borrowernumber    => $patron->borrowernumber,
1093
        itemnumber => undef,
1093
            itemnumber        => undef,
1094
        branchcode => $patron->branchcode,
1094
            branchcode        => $patron->branchcode,
1095
        recalldate => dt_from_string,
1095
            recalldate        => \'NOW()',
1096
        status => 'R',
1096
            item_level_recall => 0,
1097
        item_level_recall => 0,
1097
        }
1098
    })->store;
1098
    )->store;
1099
    $recall->set_cancelled;
1099
    $recall->set_cancelled;
1100
1100
1101
    is( $patron->recalls->count, 3, "Correctly gets this patron's active recalls" );
1101
    is( $patron->recalls->count, 3, "Correctly gets this patron's active recalls" );
(-)a/t/db_dependent/Koha/Recall.t (-11 / +8 lines)
Lines 71-77 my $recall1 = Koha::Recall->new({ Link Here
71
    recalldate => dt_from_string,
71
    recalldate => dt_from_string,
72
    biblionumber => $biblio1->biblionumber,
72
    biblionumber => $biblio1->biblionumber,
73
    branchcode => $branch1,
73
    branchcode => $branch1,
74
    status => 'R',
74
    status => 'requested',
75
    itemnumber => $item1->itemnumber,
75
    itemnumber => $item1->itemnumber,
76
    expirationdate => undef,
76
    expirationdate => undef,
77
    item_level_recall => 1
77
    item_level_recall => 1
Lines 82-102 is( $recall1->item->homebranch, $item1->homebranch, "Recall item relationship co Link Here
82
is( $recall1->patron->categorycode, $category1, "Recall patron relationship correctly linked" );
82
is( $recall1->patron->categorycode, $category1, "Recall patron relationship correctly linked" );
83
is( $recall1->library->branchname, Koha::Libraries->find( $branch1 )->branchname, "Recall library relationship correctly linked" );
83
is( $recall1->library->branchname, Koha::Libraries->find( $branch1 )->branchname, "Recall library relationship correctly linked" );
84
is( $recall1->checkout->itemnumber, $item1->itemnumber, "Recall checkout relationship correctly linked" );
84
is( $recall1->checkout->itemnumber, $item1->itemnumber, "Recall checkout relationship correctly linked" );
85
is( $recall1->requested, 1, "Recall has been requested" );
85
ok( $recall1->requested, "Recall has been requested" );
86
86
87
is( $recall1->should_be_overdue, 1, "Correctly calculated that recall should be marked overdue" );
87
is( $recall1->should_be_overdue, 1, "Correctly calculated that recall should be marked overdue" );
88
$recall1->set_overdue({ interface => 'COMMANDLINE' });
88
$recall1->set_overdue({ interface => 'COMMANDLINE' });
89
is( $recall1->overdue, 1, "Recall is overdue" );
89
ok( $recall1->overdue, "Recall is overdue" );
90
90
91
$recall1->set_cancelled;
91
$recall1->set_cancelled;
92
is( $recall1->cancelled, 1, "Recall is cancelled" );
92
ok( $recall1->cancelled, "Recall is cancelled" );
93
93
94
my $recall2 = Koha::Recall->new({
94
my $recall2 = Koha::Recall->new({
95
    borrowernumber => $patron1->borrowernumber,
95
    borrowernumber => $patron1->borrowernumber,
96
    recalldate => dt_from_string,
96
    recalldate => dt_from_string,
97
    biblionumber => $biblio1->biblionumber,
97
    biblionumber => $biblio1->biblionumber,
98
    branchcode => $branch1,
98
    branchcode => $branch1,
99
    status => 'R',
100
    itemnumber => $item1->itemnumber,
99
    itemnumber => $item1->itemnumber,
101
    expirationdate => undef,
100
    expirationdate => undef,
102
    item_level_recall => 1
101
    item_level_recall => 1
Lines 143-149 my $recall3 = Koha::Recall->new({ Link Here
143
    recalldate => dt_from_string,
142
    recalldate => dt_from_string,
144
    biblionumber => $biblio1->biblionumber,
143
    biblionumber => $biblio1->biblionumber,
145
    branchcode => $branch1,
144
    branchcode => $branch1,
146
    status => 'R',
147
    itemnumber => $item1->itemnumber,
145
    itemnumber => $item1->itemnumber,
148
    expirationdate => undef,
146
    expirationdate => undef,
149
    item_level_recall => 1
147
    item_level_recall => 1
Lines 151-165 my $recall3 = Koha::Recall->new({ Link Here
151
149
152
# test that recall gets T status
150
# test that recall gets T status
153
$recall3->start_transfer;
151
$recall3->start_transfer;
154
is( $recall3->in_transit, 1, "Recall is in transit" );
152
ok( $recall3->in_transit, "Recall is in transit" );
155
153
156
$recall3->revert_transfer;
154
$recall3->revert_transfer;
157
is( $recall3->requested, 1, "Recall transfer has been cancelled and the status reverted" );
155
ok( $recall3->requested, "Recall transfer has been cancelled and the status reverted" );
158
is( $recall3->itemnumber, $item1->itemnumber, "Item persists for item-level recall" );
156
is( $recall3->itemnumber, $item1->itemnumber, "Item persists for item-level recall" );
159
157
160
# for testing purposes, pretend the item gets checked out
158
# for testing purposes, pretend the item gets checked out
161
$recall3->set_finished;
159
$recall3->set_fulfilled;
162
is( $recall3->finished, 1, "Recall has been fulfilled" );
160
ok( $recall3->fulfilled, "Recall has been fulfilled" );
163
161
164
C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
162
C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
165
my $recall4 = Koha::Recall->new({
163
my $recall4 = Koha::Recall->new({
Lines 167-173 my $recall4 = Koha::Recall->new({ Link Here
167
    recalldate => dt_from_string,
165
    recalldate => dt_from_string,
168
    biblionumber => $biblio1->biblionumber,
166
    biblionumber => $biblio1->biblionumber,
169
    branchcode => $branch1,
167
    branchcode => $branch1,
170
    status => 'R',
171
    itemnumber => undef,
168
    itemnumber => undef,
172
    expirationdate => undef,
169
    expirationdate => undef,
173
    item_level_recall => 0,
170
    item_level_recall => 0,
(-)a/t/db_dependent/Koha/Recalls.t (-1 / +1 lines)
Lines 170-175 ok( $recall->cancelled, "Recall cancelled with move_recall" ); Link Here
170
});
170
});
171
$message = Koha::Recalls->move_recall({ recall_id => $recall->recall_id, item => $item2, borrowernumber => $patron1->borrowernumber });
171
$message = Koha::Recalls->move_recall({ recall_id => $recall->recall_id, item => $item2, borrowernumber => $patron1->borrowernumber });
172
$recall = Koha::Recalls->find( $recall->recall_id );
172
$recall = Koha::Recalls->find( $recall->recall_id );
173
ok( $recall->finished, "Recall fulfilled with move_recall" );
173
ok( $recall->fulfilled, "Recall fulfilled with move_recall" );
174
174
175
$schema->storage->txn_rollback();
175
$schema->storage->txn_rollback();
(-)a/t/db_dependent/XSLT.t (-2 lines)
Lines 147-153 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
147
        biblionumber    => $item->biblionumber,
147
        biblionumber    => $item->biblionumber,
148
        itemnumber      => $item->itemnumber,
148
        itemnumber      => $item->itemnumber,
149
        branchcode      => $item->holdingbranch,
149
        branchcode      => $item->holdingbranch,
150
        status          => 'R',
151
    }});
150
    }});
152
    $recall->set_waiting;
151
    $recall->set_waiting;
153
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
152
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
154
- 

Return to bug 19532