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

(-)a/C4/Circulation.pm (-2 / +114 lines)
Lines 299-304 The item was reserved. The value is a reference-to-hash whose keys are fields fr Link Here
299
299
300
The item was eligible to be transferred. Barring problems communicating with the database, the transfer should indeed have succeeded. The value should be ignored.
300
The item was eligible to be transferred. Barring problems communicating with the database, the transfer should indeed have succeeded. The value should be ignored.
301
301
302
=item C<RecallPlacedAtHoldingBranch>
303
304
A recall for this item was found, and the transfer has already been completed as the item's branch matches the recall's pickup branch.
305
306
=item C<RecallFound>
307
308
A recall for this item was found, and the item needs to be transferred to the recall's pickup branch.
309
302
=back
310
=back
303
311
304
=back
312
=back
Lines 360-365 sub transferbook { Link Here
360
        $dotransfer = 1;
368
        $dotransfer = 1;
361
    }
369
    }
362
370
371
    # find recall
372
    my $recall = Koha::Recalls->find({ itemnumber => $itemnumber, status => 'T' });
373
    if ( defined $recall and C4::Context->preference('UseRecalls') ) {
374
        # do a transfer if the recall branch is different to the item holding branch
375
        if ( $recall->branchcode eq $fbr ) {
376
            $dotransfer = 0;
377
            $messages->{'RecallPlacedAtHoldingBranch'} = 1;
378
        } else {
379
            $dotransfer = 1;
380
            $messages->{'RecallFound'} = $recall;
381
        }
382
    }
383
363
    #actually do the transfer....
384
    #actually do the transfer....
364
    if ($dotransfer) {
385
    if ($dotransfer) {
365
        ModItemTransfer( $itemnumber, $fbr, $tbr, $trigger );
386
        ModItemTransfer( $itemnumber, $fbr, $tbr, $trigger );
Lines 705-710 sticky due date is invalid or due date in the past Link Here
705
726
706
if the borrower borrows to much things
727
if the borrower borrows to much things
707
728
729
=head3 RECALLED
730
731
recalled by someone else
732
708
=cut
733
=cut
709
734
710
sub CanBookBeIssued {
735
sub CanBookBeIssued {
Lines 1056-1062 sub CanBookBeIssued { Link Here
1056
        }
1081
        }
1057
    }
1082
    }
1058
1083
1059
    unless ( $ignore_reserves ) {
1084
    my $recall;
1085
    # CHECK IF ITEM HAS BEEN RECALLED BY ANOTHER PATRON
1086
    # Only bother doing this if UseRecalls is enabled and the item is recallable
1087
    # Don't look at recalls that are in transit
1088
    if ( C4::Context->preference('UseRecalls') and $item_object->can_be_waiting_recall ) {
1089
        my @recalls = $biblio->recalls;
1090
1091
        foreach my $r ( @recalls ) {
1092
            if ( $r->itemnumber == $item_object->itemnumber and
1093
                $r->borrowernumber == $patron->borrowernumber and
1094
                $r->waiting ) {
1095
                # this item is already waiting for this borrower and the recall can be fulfilled
1096
                last;
1097
            }
1098
            elsif ( $r->itemnumber == $item_object->itemnumber and
1099
                $r->in_transit ) {
1100
                # recalled item is in transit
1101
                $issuingimpossible{RECALLED_INTRANSIT} = $r->branchcode;
1102
            }
1103
            elsif ( $r->item_level_recall and
1104
                $r->itemnumber == $item_object->itemnumber and
1105
                $r->borrowernumber != $patron->borrowernumber and
1106
                !$r->in_transit ) {
1107
                # this specific item has been recalled by a different patron
1108
                $needsconfirmation{RECALLED} = $r;
1109
                $recall = $r;
1110
                last;
1111
            }
1112
            elsif ( !$r->item_level_recall and
1113
                $r->borrowernumber != $patron->borrowernumber and
1114
                !$r->in_transit ) {
1115
                # a different patron has placed a biblio-level recall and this item is eligible to fill it
1116
                $needsconfirmation{RECALLED} = $r;
1117
                $recall = $r;
1118
                last;
1119
            }
1120
        }
1121
    }
1122
1123
    unless ( $ignore_reserves and defined $recall ) {
1060
        # See if the item is on reserve.
1124
        # See if the item is on reserve.
1061
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1125
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1062
        if ($restype) {
1126
        if ($restype) {
Lines 1335-1340 AddIssue does the following things : Link Here
1335
          * RESERVE PLACED ?
1399
          * RESERVE PLACED ?
1336
              - fill reserve if reserve to this patron
1400
              - fill reserve if reserve to this patron
1337
              - cancel reserve or not, otherwise
1401
              - cancel reserve or not, otherwise
1402
          * RECALL PLACED ?
1403
              - fill recall if recall to this patron
1404
              - cancel recall or not
1405
              - revert recall's waiting status or not
1338
          * TRANSFERT PENDING ?
1406
          * TRANSFERT PENDING ?
1339
              - complete the transfert
1407
              - complete the transfert
1340
          * ISSUE THE BOOK
1408
          * ISSUE THE BOOK
Lines 1349-1354 sub AddIssue { Link Here
1349
    my $onsite_checkout = $params && $params->{onsite_checkout} ? 1 : 0;
1417
    my $onsite_checkout = $params && $params->{onsite_checkout} ? 1 : 0;
1350
    my $switch_onsite_checkout = $params && $params->{switch_onsite_checkout};
1418
    my $switch_onsite_checkout = $params && $params->{switch_onsite_checkout};
1351
    my $auto_renew = $params && $params->{auto_renew};
1419
    my $auto_renew = $params && $params->{auto_renew};
1420
    my $cancel_recall = $params && $params->{cancel_recall};
1421
    my $recall_id = $params && $params->{recall_id};
1352
    my $dbh          = C4::Context->dbh;
1422
    my $dbh          = C4::Context->dbh;
1353
    my $barcodecheck = CheckValidBarcode($barcode);
1423
    my $barcodecheck = CheckValidBarcode($barcode);
1354
1424
Lines 1420-1425 sub AddIssue { Link Here
1420
                AddReturn( $item_object->barcode, C4::Context->userenv->{'branch'} );
1490
                AddReturn( $item_object->barcode, C4::Context->userenv->{'branch'} );
1421
            }
1491
            }
1422
1492
1493
            Koha::Recalls->move_recall({ action => $cancel_recall, recall_id => $recall_id, itemnumber => $item_object->itemnumber, borrowernumber => $borrower->{borrowernumber} }) if C4::Context->preference('UseRecalls');
1494
1423
            C4::Reserves::MoveReserve( $item_object->itemnumber, $borrower->{'borrowernumber'}, $cancelreserve );
1495
            C4::Reserves::MoveReserve( $item_object->itemnumber, $borrower->{'borrowernumber'}, $cancelreserve );
1424
1496
1425
            # Starting process for transfer job (checking transfert and validate it if we have one)
1497
            # Starting process for transfer job (checking transfert and validate it if we have one)
Lines 1900-1905 Value 1 if return is successful. Link Here
1900
1972
1901
If AutomaticItemReturn is disabled, return branch is given as value of NeedsTransfer.
1973
If AutomaticItemReturn is disabled, return branch is given as value of NeedsTransfer.
1902
1974
1975
=item C<RecallFound>
1976
1977
This item can fill a recall. The recall object is returned. If the recall pickup branch differs from
1978
the branch this item is being returned at, C<RecallNeedsTransfer> is also returned which contains this
1979
branchcode.
1980
1981
=item C<TransferredRecall>
1982
1983
This item has been transferred to this branch to fill a recall. The recall object is returned.
1984
1903
=back
1985
=back
1904
1986
1905
C<$iteminformation> is a reference-to-hash, giving information about the
1987
C<$iteminformation> is a reference-to-hash, giving information about the
Lines 2150-2155 sub AddReturn { Link Here
2150
        }
2232
        }
2151
    }
2233
    }
2152
2234
2235
    # find recalls...
2236
    # check if this item is recallable first, which includes checking if UseRecalls syspref is enabled
2237
    my $recall = undef;
2238
    $recall = $item->check_recalls if $item->can_be_waiting_recall;
2239
    if ( defined $recall ) {
2240
        $messages->{RecallFound} = $recall;
2241
        if ( $recall->branchcode ne $branch ) {
2242
            $messages->{RecallNeedsTransfer} = $branch;
2243
        }
2244
    }
2245
2153
    # find reserves.....
2246
    # find reserves.....
2154
    # launch the Checkreserves routine to find any holds
2247
    # launch the Checkreserves routine to find any holds
2155
    my ($resfound, $resrec);
2248
    my ($resfound, $resrec);
Lines 2208-2215 sub AddReturn { Link Here
2208
        $request->status('RET') if $request;
2301
        $request->status('RET') if $request;
2209
    }
2302
    }
2210
2303
2304
    my $transfer_recall = Koha::Recalls->find({ itemnumber => $item->itemnumber, status => 'T' }); # all recalls that have triggered a transfer will have an allocated itemnumber
2305
    if ( $transfer_recall and
2306
         $transfer_recall->branchcode eq $branch and
2307
         C4::Context->preference('UseRecalls') ) {
2308
        $messages->{TransferredRecall} = $transfer_recall;
2309
    }
2310
2211
    # Transfer to returnbranch if Automatic transfer set or append message NeedsTransfer
2311
    # Transfer to returnbranch if Automatic transfer set or append message NeedsTransfer
2212
    if (!$is_in_rotating_collection && ($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $returnbranch) and not $messages->{'WrongTransfer'}){
2312
    if (!$is_in_rotating_collection && ($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $returnbranch) and not $messages->{'WrongTransfer'} and not $messages->{TransferredRecall} and not $messages->{RecallNeedsTransfer} ){
2213
        my $BranchTransferLimitsType = C4::Context->preference("BranchTransferLimitsType") eq 'itemtype' ? 'effective_itemtype' : 'ccode';
2313
        my $BranchTransferLimitsType = C4::Context->preference("BranchTransferLimitsType") eq 'itemtype' ? 'effective_itemtype' : 'ccode';
2214
        if  (C4::Context->preference("AutomaticItemReturn"    ) or
2314
        if  (C4::Context->preference("AutomaticItemReturn"    ) or
2215
            (C4::Context->preference("UseBranchTransferLimits") and
2315
            (C4::Context->preference("UseBranchTransferLimits") and
Lines 2926-2931 sub CanBookBeRenewed { Link Here
2926
        }
3026
        }
2927
    }
3027
    }
2928
3028
3029
    my $recall = undef;
3030
    $recall = $item->check_recalls if $item->can_be_waiting_recall;
3031
    if ( defined $recall ) {
3032
        if ( $recall->item_level_recall ) {
3033
            # item-level recall. check if this item is the recalled item, otherwise renewal will be allowed
3034
            return ( 0, 'recalled' ) if ( $recall->itemnumber == $item->itemnumber );
3035
        } else {
3036
            # biblio-level recall, so only disallow renewal if the biblio-level recall has been fulfilled by a different item
3037
            return ( 0, 'recalled' ) unless ( $recall->waiting );
3038
        }
3039
    }
3040
2929
    my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber);
3041
    my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber);
2930
3042
2931
    # This item can fill one or more unfilled reserve, can those unfilled reserves
3043
    # This item can fill one or more unfilled reserve, can those unfilled reserves
(-)a/C4/Reserves.pm (+5 lines)
Lines 351-356 sub CanBookBeReserved{ Link Here
351
         { status => libraryNotPickupLocation },   if given branchcode is not configured to be a pickup location
351
         { status => libraryNotPickupLocation },   if given branchcode is not configured to be a pickup location
352
         { status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode
352
         { status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode
353
         { status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups.
353
         { status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups.
354
         { status => recall }, if the borrower has already placed a recall on this item
354
355
355
=cut
356
=cut
356
357
Lines 384-389 sub CanItemBeReserved { Link Here
384
    return { status =>'itemAlreadyOnHold' }
385
    return { status =>'itemAlreadyOnHold' }
385
      if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count();
386
      if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count();
386
387
388
    # check if a recall exists on this item from this borrower
389
    return { status => 'recall' }
390
      if Koha::Recalls->search({ borrowernumber => $borrowernumber, itemnumber => $itemnumber, old => undef })->count;
391
387
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
392
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
388
393
389
    my $querycount = q{
394
    my $querycount = q{
(-)a/C4/Search.pm (+9 lines)
Lines 1890-1895 sub searchResults { Link Here
1890
        my $can_place_holds       = 0;
1890
        my $can_place_holds       = 0;
1891
        my $item_onhold_count     = 0;
1891
        my $item_onhold_count     = 0;
1892
        my $notforloan_count      = 0;
1892
        my $notforloan_count      = 0;
1893
        my $item_recalled_count   = 0;
1893
        my $items_count           = scalar(@fields);
1894
        my $items_count           = scalar(@fields);
1894
        my $maxitems_pref = C4::Context->preference('maxItemsinSearchResults');
1895
        my $maxitems_pref = C4::Context->preference('maxItemsinSearchResults');
1895
        my $maxitems = $maxitems_pref ? $maxitems_pref - 1 : 1;
1896
        my $maxitems = $maxitems_pref ? $maxitems_pref - 1 : 1;
Lines 1984-1989 sub searchResults { Link Here
1984
                # is item on the reserve shelf?
1985
                # is item on the reserve shelf?
1985
                my $reservestatus = '';
1986
                my $reservestatus = '';
1986
1987
1988
                # is item a waiting recall?
1989
                my $recallstatus = '';
1990
1987
                unless ($item->{withdrawn}
1991
                unless ($item->{withdrawn}
1988
                        || $item->{itemlost}
1992
                        || $item->{itemlost}
1989
                        || $item->{damaged}
1993
                        || $item->{damaged}
Lines 2005-2010 sub searchResults { Link Here
2005
                    #
2009
                    #
2006
                    ($transfertwhen, $transfertfrom, $transfertto) = C4::Circulation::GetTransfers($item->{itemnumber});
2010
                    ($transfertwhen, $transfertfrom, $transfertto) = C4::Circulation::GetTransfers($item->{itemnumber});
2007
                    $reservestatus = C4::Reserves::GetReserveStatus( $item->{itemnumber} );
2011
                    $reservestatus = C4::Reserves::GetReserveStatus( $item->{itemnumber} );
2012
                    $recallstatus = 'Waiting' if Koha::Recalls->search({ itemnumber => $item->{itemnumber}, status => 'W' })->count;
2008
                }
2013
                }
2009
2014
2010
                # item is withdrawn, lost, damaged, not for loan, reserved or in transit
2015
                # item is withdrawn, lost, damaged, not for loan, reserved or in transit
Lines 2013-2018 sub searchResults { Link Here
2013
                    || $item->{damaged}
2018
                    || $item->{damaged}
2014
                    || $item->{notforloan}
2019
                    || $item->{notforloan}
2015
                    || $reservestatus eq 'Waiting'
2020
                    || $reservestatus eq 'Waiting'
2021
                    || $recallstatus eq 'Waiting'
2016
                    || ($transfertwhen && $transfertwhen ne ''))
2022
                    || ($transfertwhen && $transfertwhen ne ''))
2017
                {
2023
                {
2018
                    $withdrawn_count++        if $item->{withdrawn};
2024
                    $withdrawn_count++        if $item->{withdrawn};
Lines 2020-2025 sub searchResults { Link Here
2020
                    $itemdamaged_count++     if $item->{damaged};
2026
                    $itemdamaged_count++     if $item->{damaged};
2021
                    $item_in_transit_count++ if $transfertwhen && $transfertwhen ne '';
2027
                    $item_in_transit_count++ if $transfertwhen && $transfertwhen ne '';
2022
                    $item_onhold_count++     if $reservestatus eq 'Waiting';
2028
                    $item_onhold_count++     if $reservestatus eq 'Waiting';
2029
                    $item_recalled_count++   if $recallstatus eq 'Waiting';
2023
                    $item->{status} = ($item->{withdrawn}//q{}) . "-" . ($item->{itemlost}//q{}) . "-" . ($item->{damaged}//q{}) . "-" . ($item->{notforloan}//q{});
2030
                    $item->{status} = ($item->{withdrawn}//q{}) . "-" . ($item->{itemlost}//q{}) . "-" . ($item->{damaged}//q{}) . "-" . ($item->{notforloan}//q{});
2024
2031
2025
                    # can place a hold on a item if
2032
                    # can place a hold on a item if
Lines 2041-2046 sub searchResults { Link Here
2041
                        $other_items->{$key}->{$_} = $item->{$_};
2048
                        $other_items->{$key}->{$_} = $item->{$_};
2042
                    }
2049
                    }
2043
                    $other_items->{$key}->{intransit} = ( $transfertwhen ne '' ) ? 1 : 0;
2050
                    $other_items->{$key}->{intransit} = ( $transfertwhen ne '' ) ? 1 : 0;
2051
                    $other_items->{$key}->{recalled} = ($recallstatus) ? 1 : 0;
2044
                    $other_items->{$key}->{onhold} = ($reservestatus) ? 1 : 0;
2052
                    $other_items->{$key}->{onhold} = ($reservestatus) ? 1 : 0;
2045
                    $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value and $item->{notforloan};
2053
                    $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value and $item->{notforloan};
2046
                    $other_items->{$key}->{count}++ if $item->{$hbranch};
2054
                    $other_items->{$key}->{count}++ if $item->{$hbranch};
Lines 2115-2120 sub searchResults { Link Here
2115
        $oldbiblio->{damagedcount}         = $itemdamaged_count;
2123
        $oldbiblio->{damagedcount}         = $itemdamaged_count;
2116
        $oldbiblio->{intransitcount}       = $item_in_transit_count;
2124
        $oldbiblio->{intransitcount}       = $item_in_transit_count;
2117
        $oldbiblio->{onholdcount}          = $item_onhold_count;
2125
        $oldbiblio->{onholdcount}          = $item_onhold_count;
2126
        $oldbiblio->{recalledcount}        = $item_recalled_count;
2118
        $oldbiblio->{orderedcount}         = $ordered_count;
2127
        $oldbiblio->{orderedcount}         = $ordered_count;
2119
        $oldbiblio->{notforloancount}      = $notforloan_count;
2128
        $oldbiblio->{notforloancount}      = $notforloan_count;
2120
2129
(-)a/C4/XSLT.pm (-1 / +7 lines)
Lines 321-327 sub buildKohaItemsNamespace { Link Here
321
        my $status;
321
        my $status;
322
        my $substatus = '';
322
        my $substatus = '';
323
323
324
        if ($item->has_pending_hold) {
324
        my $recalls = Koha::Recalls->search({ itemnumber => $item->itemnumber, status => 'W' });
325
326
        if ( $recalls->count ) {
327
            # recalls take priority over holds
328
            $status = 'Waiting';
329
        }
330
        elsif ( $item->has_pending_hold ) {
325
            $status = 'Pending hold';
331
            $status = 'Pending hold';
326
        }
332
        }
327
        elsif ( $item->holds->waiting->count ) {
333
        elsif ( $item->holds->waiting->count ) {
(-)a/Koha/Biblio.pm (+105 lines)
Lines 816-821 sub to_api_mapping { Link Here
816
    };
816
    };
817
}
817
}
818
818
819
=head3 recalls
820
821
    my @recalls = $biblio->recalls;
822
823
Return all active recalls attached to this biblio, sorted by oldest first
824
825
=cut
826
827
sub recalls {
828
    my ( $self ) = @_;
829
    my @recalls_rs = Koha::Recalls->search({ biblionumber => $self->biblionumber, old => undef }, { order_by => { -asc => 'recalldate' } });
830
    return @recalls_rs;
831
}
832
833
=head3 can_be_recalled
834
835
    my @items_for_recall = $biblio->can_be_recalled({ patron => $patron_object });
836
837
Does biblio-level checks and returns the items attached to this biblio that are available for recall
838
839
=cut
840
841
sub can_be_recalled {
842
    my ( $self, $params ) = @_;
843
844
    return 0 if !( C4::Context->preference('UseRecalls') );
845
846
    my $patron = $params->{patron};
847
848
    my $branchcode = C4::Context->userenv->{'branch'};
849
    if ( C4::Context->preference('CircControl') eq 'PatronLibrary' and $patron ) {
850
        $branchcode = $patron->branchcode;
851
    }
852
853
    my @all_items = Koha::Items->search({ biblionumber => $self->biblionumber });
854
855
    # if there are no available items at all, no recall can be placed
856
    return 0 if ( scalar @items == 0 );
857
858
    my @itemtypes;
859
    my @itemnumbers;
860
    my @items;
861
    foreach my $item ( @all_items ) {
862
        if ( $item->can_be_recalled({ patron => $patron }) ) {
863
            push( @itemtypes, $item->effective_itemtype );
864
            push( @itemnumbers, $item->itemnumber );
865
            push( @items, $item );
866
        }
867
    }
868
869
    # Check the circulation rule for each relevant itemtype for this biblio
870
    my ( @recalls_allowed, @recalls_per_record, @on_shelf_recalls );
871
    foreach my $itemtype ( @itemtypes ) {
872
        my $rule = Koha::CirculationRules->get_effective_rules({
873
            branchcode => $branchcode,
874
            categorycode => $patron ? $patron->categorycode : undef,
875
            itemtype => $itemtype,
876
            rules => [
877
                'recalls_allowed',
878
                'recalls_per_record',
879
                'on_shelf_recalls',
880
            ],
881
        });
882
        push( @recalls_allowed, $rule->{recalls_allowed} ) if $rule;
883
        push( @recalls_per_record, $rule->{recalls_per_record} ) if $rule;
884
        push( @on_shelf_recalls, $rule->{on_shelf_recalls} ) if $rule;
885
    }
886
    my $recalls_allowed = (sort {$b <=> $a} @recalls_allowed)[0]; # take highest
887
    my $recalls_per_record = (sort {$b <=> $a} @recalls_per_record)[0]; # take highest
888
    my %on_shelf_recalls_count = ();
889
    foreach my $count ( @on_shelf_recalls ) {
890
        $on_shelf_recalls_count{$count}++;
891
    }
892
    my $on_shelf_recalls = (sort {$on_shelf_recalls_count{$b} <=> $on_shelf_recalls_count{$a}} @on_shelf_recalls)[0]; # take most common
893
894
    # check recalls allowed has been set and is not zero
895
    return 0 if ( !defined($recalls_allowed) || $recalls_allowed == 0 );
896
897
    if ( $patron ) {
898
        # check borrower has not reached open recalls allowed limit
899
        return 0 if ( $patron->recalls->count >= $recalls_allowed );
900
901
        # check borrower has not reached open recalls allowed per record limit
902
        return 0 if ( $patron->recalls({ biblionumber => $self->biblionumber })->count >= $recalls_per_record );
903
904
        # check if any of the items under this biblio are already checked out by this borrower
905
        return 0 if ( Koha::Checkouts->search({ itemnumber => [ @itemnumbers ], borrowernumber => $patron->borrowernumber })->count > 0 );
906
    }
907
908
    # check item availability
909
    my $checked_out_count = 0;
910
    foreach (@items) {
911
        if ( Koha::Checkouts->search({ itemnumber => $_->itemnumber })->count > 0 ){ $checked_out_count++; }
912
    }
913
914
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
915
    return 0 if ( $on_shelf_recalls eq 'all' && $checked_out_count < scalar @items );
916
917
    # can't recall if no items have been checked out
918
    return 0 if ( $checked_out_count == 0 );
919
920
    # can recall
921
    return @items;
922
}
923
819
=head2 Internal methods
924
=head2 Internal methods
820
925
821
=head3 type
926
=head3 type
(-)a/Koha/Item.pm (+176 lines)
Lines 842-847 sub _after_item_action_hooks { Link Here
842
    );
842
    );
843
}
843
}
844
844
845
=head3 recall
846
847
    my $recall = $item->recall;
848
849
Return the relevant recall for this item
850
851
=cut
852
853
sub recall {
854
    my ( $self ) = @_;
855
    my @recalls = Koha::Recalls->search({ biblionumber => $self->biblionumber, old => undef }, { order_by => { -asc => 'recalldate' } });
856
    foreach my $recall (@recalls) {
857
        if ( $recall->item_level_recall and $recall->itemnumber == $self->itemnumber ){
858
            return $recall;
859
        }
860
    }
861
    # no item-level recall to return, so return earliest biblio-level
862
    # FIXME: eventually this will be based on priority
863
    return $recalls[0];
864
}
865
866
=head3 can_be_recalled
867
868
    if ( $item->can_be_recalled({ patron => $patron_object }) ) # do recall
869
870
Does item-level checks and returns if items can be recalled by this borrower
871
872
=cut
873
874
sub can_be_recalled {
875
    my ( $self, $params ) = @_;
876
877
    return 0 if !( C4::Context->preference('UseRecalls') );
878
879
    # check if this item is not for loan, withdrawn or lost
880
    return 0 if ( $self->notforloan != 0 );
881
    return 0 if ( $self->itemlost != 0 );
882
    return 0 if ( $self->withdrawn != 0 );
883
884
    # check if this item is not checked out - if not checked out, can't be recalled
885
    return 0 if ( !defined( $self->checkout ) );
886
887
    my $patron = $params->{patron};
888
889
    my $branchcode = C4::Context->userenv->{'branch'};
890
    if ( $patron ) {
891
        $branchcode = C4::Circulation::_GetCircControlBranch( $self->unblessed, $patron->unblessed );
892
    }
893
894
    # Check the circulation rule for each relevant itemtype for this item
895
    my $rule = Koha::CirculationRules->get_effective_rules({
896
        branchcode => $branchcode,
897
        categorycode => $patron ? $patron->categorycode : undef,
898
        itemtype => $self->effective_itemtype,
899
        rules => [
900
            'recalls_allowed',
901
            'recalls_per_record',
902
            'on_shelf_recalls',
903
        ],
904
    });
905
906
    # check recalls allowed has been set and is not zero
907
    return 0 if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
908
909
    if ( $patron ) {
910
        # check borrower has not reached open recalls allowed limit
911
        return 0 if ( $patron->recalls->count >= $rule->{recalls_allowed} );
912
913
        # check borrower has not reach open recalls allowed per record limit
914
        return 0 if ( $patron->recalls({ biblionumber => $self->biblionumber })->count >= $rule->{recalls_per_record} );
915
916
        # check if this patron has already recalled this item
917
        return 0 if ( Koha::Recalls->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber, old => undef })->count > 0 );
918
919
        # check if this patron has already checked out this item
920
        return 0 if ( Koha::Checkouts->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
921
922
        # check if this patron has already reserved this item
923
        return 0 if ( Koha::Holds->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
924
    }
925
926
    # check item availability
927
    # items are unavailable for recall if they are lost, withdrawn or notforloan
928
    my @items = Koha::Items->search({ biblionumber => $self->biblionumber, itemlost => 0, withdrawn => 0, notforloan => 0 });
929
930
    # if there are no available items at all, no recall can be placed
931
    return 0 if ( scalar @items == 0 );
932
933
    my $checked_out_count = 0;
934
    foreach (@items) {
935
        if ( Koha::Checkouts->search({ itemnumber => $_->itemnumber })->count > 0 ){ $checked_out_count++; }
936
    }
937
938
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
939
    return 0 if ( $rule->{on_shelf_recalls} eq 'all' && $checked_out_count < scalar @items );
940
941
    # can't recall if no items have been checked out
942
    return 0 if ( $checked_out_count == 0 );
943
944
    # can recall
945
    return 1;
946
}
947
948
=head3 can_be_waiting_recall
949
950
    if ( $item->can_be_waiting_recall ) { # allocate item as waiting for recall
951
952
Checks item type and branch of circ rules to return whether this item can be used to fill a recall.
953
At this point the item has already been recalled. We are now at the checkin and set waiting stage.
954
955
=cut
956
957
sub can_be_waiting_recall {
958
    my ( $self ) = @_;
959
960
    return 0 if !( C4::Context->preference('UseRecalls') );
961
962
    # check if this item is not for loan, withdrawn or lost
963
    return 0 if ( $self->notforloan != 0 );
964
    return 0 if ( $self->itemlost != 0 );
965
    return 0 if ( $self->withdrawn != 0 );
966
967
    my $branchcode = $self->holdingbranch;
968
    if ( C4::Context->preference('CircControl') eq 'PickupLibrary' and C4::Context->userenv and C4::Context->userenv->{'branch'} ) {
969
        $branchcode = C4::Context->userenv->{'branch'};
970
    } else {
971
        $branchcode = ( C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ) ? $self->homebranch : $self->holdingbranch;
972
    }
973
974
    # Check the circulation rule for each relevant itemtype for this item
975
    my $rule = Koha::CirculationRules->get_effective_rules({
976
        branchcode => $branchcode,
977
        categorycode => undef,
978
        itemtype => $self->effective_itemtype,
979
        rules => [
980
            'recalls_allowed',
981
        ],
982
    });
983
984
    # check recalls allowed has been set and is not zero
985
    return 0 if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
986
987
    # can recall
988
    return 1;
989
}
990
991
=head3 check_recalls
992
993
    my $recall = $item->check_recalls;
994
995
Get the most relevant recall for this item.
996
997
=cut
998
999
sub check_recalls {
1000
    my ( $self ) = @_;
1001
1002
    my @recalls = Koha::Recalls->search({ biblionumber => $self->biblionumber, itemnumber => [ $self->itemnumber, undef ], status => [ 'R','O','W','T' ] }, { order_by => { -asc => 'recalldate' } });
1003
1004
    my $recall;
1005
    # iterate through relevant recalls to find the best one.
1006
    # if we come across a waiting recall, use this one.
1007
    # if we have iterated through all recalls and not found a waiting recall, use the first recall in the array, which should be the oldest recall.
1008
    foreach my $r ( @recalls ) {
1009
        if ( $r->waiting ) {
1010
            $recall = $r;
1011
            last;
1012
        }
1013
    }
1014
    unless ( defined $recall ) {
1015
        $recall = $recalls[0];
1016
    }
1017
1018
    return $recall;
1019
}
1020
845
=head3 _type
1021
=head3 _type
846
1022
847
=cut
1023
=cut
(-)a/Koha/Patron.pm (+24 lines)
Lines 1712-1717 sub to_api_mapping { Link Here
1712
    };
1712
    };
1713
}
1713
}
1714
1714
1715
=head3 recalls
1716
1717
    my $recalls = $patron->recalls;
1718
1719
    my $recalls = $patron->recalls({ biblionumber => $biblionumber });
1720
1721
Return the patron's active recalls - total, or on a specific biblio
1722
1723
=cut
1724
1725
sub recalls {
1726
    my ( $self, $params ) = @_;
1727
1728
    my $biblionumber = $params->{biblionumber};
1729
1730
    my $recalls_rs = Koha::Recalls->search({ borrowernumber => $self->borrowernumber, old => undef });
1731
1732
    if ( $biblionumber ) {
1733
        $recalls_rs = Koha::Recalls->search({ borrowernumber => $self->borrowernumber, old => undef, biblionumber => $biblionumber });
1734
    }
1735
1736
    return $recalls_rs;
1737
}
1738
1715
=head2 Internal methods
1739
=head2 Internal methods
1716
1740
1717
=head3 _type
1741
=head3 _type
(-)a/Koha/Template/Plugin/Biblio.pm (+9 lines)
Lines 27-32 use Koha::Biblios; Link Here
27
use Koha::Patrons;
27
use Koha::Patrons;
28
use Koha::ArticleRequests;
28
use Koha::ArticleRequests;
29
use Koha::ArticleRequest::Status;
29
use Koha::ArticleRequest::Status;
30
use Koha::Recalls;
30
31
31
sub HoldsCount {
32
sub HoldsCount {
32
    my ( $self, $biblionumber ) = @_;
33
    my ( $self, $biblionumber ) = @_;
Lines 63-66 sub CanArticleRequest { Link Here
63
    return $biblio ? $biblio->can_article_request( $borrower ) : 0;
64
    return $biblio ? $biblio->can_article_request( $borrower ) : 0;
64
}
65
}
65
66
67
sub RecallsCount {
68
    my ( $self, $biblionumber ) = @_;
69
70
    my $recalls = Koha::Recalls->search({ biblionumber => $biblionumber, old => undef });
71
72
    return $recalls->count;
73
}
74
66
1;
75
1;
(-)a/t/db_dependent/Circulation.t (-2 / +243 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
use utf8;
19
use utf8;
20
20
21
use Test::More tests => 49;
21
use Test::More tests => 52;
22
use Test::MockModule;
22
use Test::MockModule;
23
use Test::Deep qw( cmp_deeply );
23
use Test::Deep qw( cmp_deeply );
24
24
Lines 277-283 Koha::CirculationRules->set_rules( Link Here
277
277
278
my ( $reused_itemnumber_1, $reused_itemnumber_2 );
278
my ( $reused_itemnumber_1, $reused_itemnumber_2 );
279
subtest "CanBookBeRenewed tests" => sub {
279
subtest "CanBookBeRenewed tests" => sub {
280
    plan tests => 83;
280
    plan tests => 87;
281
281
282
    C4::Context->set_preference('ItemsDeniedRenewal','');
282
    C4::Context->set_preference('ItemsDeniedRenewal','');
283
    # Generate test biblio
283
    # Generate test biblio
Lines 1260-1265 subtest "CanBookBeRenewed tests" => sub { Link Here
1260
            $item_3->itemcallnumber || '' ),
1260
            $item_3->itemcallnumber || '' ),
1261
        "Account line description must not contain 'Lost Items ', but be title, barcode, itemcallnumber"
1261
        "Account line description must not contain 'Lost Items ', but be title, barcode, itemcallnumber"
1262
    );
1262
    );
1263
1264
    # Recalls
1265
    t::lib::Mocks::mock_preference('UseRecalls', 1);
1266
    Koha::CirculationRules->set_rules({
1267
        categorycode => undef,
1268
        branchcode => undef,
1269
        itemtype => undef,
1270
        rules => {
1271
            recalls_allowed => 10,
1272
            renewalsallowed => 5,
1273
        },
1274
    });
1275
    my $recall_borrower = $builder->build_object({ class => 'Koha::Patrons' });
1276
    my $recall_biblio = $builder->build_object({ class => 'Koha::Biblios' });
1277
    my $recall_item1 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1278
    my $recall_item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1279
1280
    AddIssue( $renewing_borrower, $recall_item1->barcode );
1281
1282
    # item-level and this item: renewal not allowed
1283
    my $recall = Koha::Recall->new({
1284
        biblionumber => $recall_item1->biblionumber,
1285
        itemnumber => $recall_item1->itemnumber,
1286
        borrowernumber => $recall_borrower->borrowernumber,
1287
        branchcode => $recall_borrower->branchcode,
1288
        item_level_recall => 1,
1289
        status => 'R',
1290
    })->store;
1291
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1292
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1293
    $recall->set_cancelled;
1294
1295
    # biblio-level requested recall: renewal not allowed
1296
    $recall = Koha::Recall->new({
1297
        biblionumber => $recall_item1->biblionumber,
1298
        itemnumber => undef,
1299
        borrowernumber => $recall_borrower->borrowernumber,
1300
        branchcode => $recall_borrower->branchcode,
1301
        item_level_recall => 0,
1302
        status => 'R',
1303
    })->store;
1304
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1305
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1306
    $recall->set_cancelled;
1307
1308
    # item-level and not this item: renewal allowed
1309
    $recall = Koha::Recall->new({
1310
        biblionumber => $recall_item2->biblionumber,
1311
        itemnumber => $recall_item2->itemnumber,
1312
        borrowernumber => $recall_borrower->borrowernumber,
1313
        branchcode => $recall_borrower->branchcode,
1314
        item_level_recall => 1,
1315
        status => 'R',
1316
    })->store;
1317
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1318
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1319
    $recall->set_cancelled;
1320
1321
    # biblio-level waiting recall: renewal allowed
1322
    $recall = Koha::Recall->new({
1323
        biblionumber => $recall_item1->biblionumber,
1324
        itemnumber => undef,
1325
        borrowernumber => $recall_borrower->borrowernumber,
1326
        branchcode => $recall_borrower->branchcode,
1327
        item_level_recall => 0,
1328
        status => 'R',
1329
    })->store;
1330
    $recall->set_waiting({ item => $recall_item1 });
1331
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1332
    is( $renewokay, 1, 'Can renew item if biblio-level recall has already been allocated an item' );
1333
    $recall->set_cancelled;
1263
};
1334
};
1264
1335
1265
subtest "GetUpcomingDueIssues" => sub {
1336
subtest "GetUpcomingDueIssues" => sub {
Lines 1740-1745 subtest 'AddIssue & AllowReturnToBranch' => sub { Link Here
1740
    # TODO t::lib::Mocks::mock_preference('AllowReturnToBranch', 'homeorholdingbranch');
1811
    # TODO t::lib::Mocks::mock_preference('AllowReturnToBranch', 'homeorholdingbranch');
1741
};
1812
};
1742
1813
1814
subtest 'AddIssue | recalls' => sub {
1815
    plan tests => 3;
1816
1817
    t::lib::Mocks::mock_preference("UseRecalls", 1);
1818
    t::lib::Mocks::mock_preference("item-level_itypes", 1);
1819
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons' });
1820
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons' });
1821
    my $item = $builder->build_sample_item;
1822
    Koha::CirculationRules->set_rules({
1823
        branchcode => undef,
1824
        itemtype => undef,
1825
        categorycode => undef,
1826
        rules => {
1827
            recalls_allowed => 10,
1828
        },
1829
    });
1830
1831
    # checking out item that they have recalled
1832
    my $recall1 = Koha::Recall->new({
1833
        borrowernumber => $patron1->borrowernumber,
1834
        biblionumber => $item->biblionumber,
1835
        itemnumber => $item->itemnumber,
1836
        item_level_recall => 1,
1837
        branchcode => $patron1->branchcode,
1838
        status => 'R',
1839
    })->store;
1840
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall1->recall_id } );
1841
    $recall1 = Koha::Recalls->find( $recall1->recall_id );
1842
    is( $recall1->finished, 1, 'Recall was fulfilled when patron checked out item' );
1843
    AddReturn( $item->barcode, $item->homebranch );
1844
1845
    # this item is has a recall request. cancel recall
1846
    my $recall2 = Koha::Recall->new({
1847
        borrowernumber => $patron2->borrowernumber,
1848
        biblionumber => $item->biblionumber,
1849
        itemnumber => $item->itemnumber,
1850
        item_level_recall => 1,
1851
        branchcode => $patron2->branchcode,
1852
        status => 'R',
1853
    })->store;
1854
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall2->recall_id, cancel_recall => 'cancel' } );
1855
    $recall2 = Koha::Recalls->find( $recall2->recall_id );
1856
    is( $recall2->cancelled, 1, 'Recall was cancelled when patron checked out item' );
1857
    AddReturn( $item->barcode, $item->homebranch );
1858
1859
    # this item is waiting to fulfill a recall. revert recall
1860
    my $recall3 = Koha::Recall->new({
1861
        borrowernumber => $patron2->borrowernumber,
1862
        biblionumber => $item->biblionumber,
1863
        itemnumber => $item->itemnumber,
1864
        item_level_recall => 1,
1865
        branchcode => $patron2->branchcode,
1866
        status => 'R',
1867
    })->store;
1868
    $recall3->set_waiting;
1869
    AddIssue( $patron1->unblessed, $item->barcode, undef, undef, undef, undef, { recall_id => $recall3->recall_id, cancel_recall => 'revert' } );
1870
    $recall3 = Koha::Recalls->find( $recall3->recall_id );
1871
    is( $recall3->requested, 1, 'Recall was reverted from waiting when patron checked out item' );
1872
    AddReturn( $item->barcode, $item->homebranch );
1873
};
1874
1875
1743
subtest 'CanBookBeIssued + Koha::Patron->is_debarred|has_overdues' => sub {
1876
subtest 'CanBookBeIssued + Koha::Patron->is_debarred|has_overdues' => sub {
1744
    plan tests => 8;
1877
    plan tests => 8;
1745
1878
Lines 3587-3592 subtest 'CanBookBeIssued | notforloan' => sub { Link Here
3587
    # TODO test with AllowNotForLoanOverride = 1
3720
    # TODO test with AllowNotForLoanOverride = 1
3588
};
3721
};
3589
3722
3723
subtest 'CanBookBeIssued | recalls' => sub {
3724
    plan tests => 2;
3725
3726
    t::lib::Mocks::mock_preference("UseRecalls", 1);
3727
    t::lib::Mocks::mock_preference("item-level_itypes", 1);
3728
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons' });
3729
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons' });
3730
    my $item = $builder->build_sample_item;
3731
    Koha::CirculationRules->set_rules({
3732
        branchcode => undef,
3733
        itemtype => undef,
3734
        categorycode => undef,
3735
        rules => {
3736
            recalls_allowed => 10,
3737
        },
3738
    });
3739
3740
    # item-level recall
3741
    my $recall = Koha::Recall->new({
3742
        borrowernumber => $patron1->borrowernumber,
3743
        biblionumber => $item->biblionumber,
3744
        itemnumber => $item->itemnumber,
3745
        item_level_recall => 1,
3746
        branchcode => $patron1->branchcode,
3747
        status => 'R',
3748
    })->store;
3749
3750
    my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
3751
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed an item-level recall on this item" );
3752
3753
    $recall->set_cancelled;
3754
3755
    # biblio-level recall
3756
    $recall = Koha::Recall->new({
3757
        borrowernumber => $patron1->borrowernumber,
3758
        biblionumber => $item->biblionumber,
3759
        itemnumber => undef,
3760
        item_level_recall => 0,
3761
        branchcode => $patron1->branchcode,
3762
        status => 'R',
3763
    })->store;
3764
3765
    ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron2, $item->barcode, undef, undef, undef, undef );
3766
    is( $needsconfirmation->{RECALLED}->recall_id, $recall->recall_id, "Another patron has placed a biblio-level recall and this item is eligible to fill it" );
3767
3768
    $recall->set_cancelled;
3769
};
3770
3590
subtest 'AddReturn should clear items.onloan for unissued items' => sub {
3771
subtest 'AddReturn should clear items.onloan for unissued items' => sub {
3591
    plan tests => 1;
3772
    plan tests => 1;
3592
3773
Lines 3602-3607 subtest 'AddReturn should clear items.onloan for unissued items' => sub { Link Here
3602
    is( $item->onloan, undef, 'AddReturn did clear items.onloan' );
3783
    is( $item->onloan, undef, 'AddReturn did clear items.onloan' );
3603
};
3784
};
3604
3785
3786
subtest 'AddReturn | recalls' => sub {
3787
    plan tests => 3;
3788
3789
    t::lib::Mocks::mock_preference("UseRecalls", 1);
3790
    t::lib::Mocks::mock_preference("item-level_itypes", 1);
3791
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons' });
3792
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons' });
3793
    my $item1 = $builder->build_sample_item;
3794
    Koha::CirculationRules->set_rules({
3795
        branchcode => undef,
3796
        itemtype => undef,
3797
        categorycode => undef,
3798
        rules => {
3799
            recalls_allowed => 10,
3800
        },
3801
    });
3802
3803
    # this item can fill a recall with pickup at this branch
3804
    AddIssue( $patron1->unblessed, $item1->barcode );
3805
    my $recall1 = Koha::Recall->new({
3806
        borrowernumber => $patron2->borrowernumber,
3807
        biblionumber => $item1->biblionumber,
3808
        itemnumber => $item1->itemnumber,
3809
        item_level_recall => 1,
3810
        branchcode => $item1->homebranch,
3811
        status => 'R',
3812
    })->store;
3813
    my ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
3814
    is( $messages->{RecallFound}->recall_id, $recall1->recall_id, "Recall found" );
3815
    $recall1->set_cancelled;
3816
3817
    # this item can fill a recall but needs transfer
3818
    AddIssue( $patron1->unblessed, $item1->barcode );
3819
    $recall1 = Koha::Recall->new({
3820
        borrowernumber => $patron2->borrowernumber,
3821
        biblionumber => $item1->biblionumber,
3822
        itemnumber => $item1->itemnumber,
3823
        item_level_recall => 1,
3824
        branchcode => $patron2->branchcode,
3825
        status => 'R',
3826
    })->store;
3827
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $item1->homebranch );
3828
    is( $messages->{RecallNeedsTransfer}, $item1->homebranch, "Recall requiring transfer found" );
3829
    $recall1->set_cancelled;
3830
3831
    # this item is already in transit, do not ask to transfer
3832
    AddIssue( $patron1->unblessed, $item1->barcode );
3833
    $recall1 = Koha::Recall->new({
3834
        borrowernumber => $patron2->borrowernumber,
3835
        biblionumber => $item1->biblionumber,
3836
        itemnumber => $item1->itemnumber,
3837
        item_level_recall => 1,
3838
        branchcode => $patron2->branchcode,
3839
        status => 'R',
3840
    })->store;
3841
    $recall1->start_transfer;
3842
    ( $doreturn, $messages, $iteminfo, $borrowerinfo ) = AddReturn( $item1->barcode, $patron2->branchcode );
3843
    is( $messages->{TransferredRecall}->recall_id, $recall1->recall_id, "In transit recall found" );
3844
    $recall1->set_cancelled;
3845
};
3605
3846
3606
subtest 'AddRenewal and AddIssuingCharge tests' => sub {
3847
subtest 'AddRenewal and AddIssuingCharge tests' => sub {
3607
3848
(-)a/t/db_dependent/Circulation/transferbook.t (-1 / +33 lines)
Lines 27-32 use Koha::DateUtils qw( dt_from_string ); Link Here
27
use Koha::Item::Transfers;
27
use Koha::Item::Transfers;
28
28
29
my $builder = t::lib::TestBuilder->new;
29
my $builder = t::lib::TestBuilder->new;
30
my $schema = Koha::Database->new->schema;
31
32
$schema->storage->txn_begin;
30
33
31
subtest 'transfer a non-existant item' => sub {
34
subtest 'transfer a non-existant item' => sub {
32
    plan tests => 2;
35
    plan tests => 2;
Lines 90-96 subtest 'field population tests' => sub { Link Here
90
#FIXME:'UseBranchTransferLimits tests missing
93
#FIXME:'UseBranchTransferLimits tests missing
91
94
92
subtest 'transfer already at destination' => sub {
95
subtest 'transfer already at destination' => sub {
93
    plan tests => 5;
96
    plan tests => 9;
94
97
95
    my $library = $builder->build_object( { class => 'Koha::Libraries' } )->store;
98
    my $library = $builder->build_object( { class => 'Koha::Libraries' } )->store;
96
    t::lib::Mocks::mock_userenv( { branchcode => $library->branchcode } );
99
    t::lib::Mocks::mock_userenv( { branchcode => $library->branchcode } );
Lines 130-135 subtest 'transfer already at destination' => sub { Link Here
130
    is( $dotransfer, 1, 'Transfer of reserved item succeeded without ignore reserves' );
133
    is( $dotransfer, 1, 'Transfer of reserved item succeeded without ignore reserves' );
131
    is( $messages->{ResFound}->{ResFound}, 'Reserved', "We found the reserve");
134
    is( $messages->{ResFound}->{ResFound}, 'Reserved', "We found the reserve");
132
    is( $messages->{ResFound}->{itemnumber}, $item->itemnumber, "We got the reserve info");
135
    is( $messages->{ResFound}->{itemnumber}, $item->itemnumber, "We got the reserve info");
136
137
    # recalls
138
    t::lib::Mocks::mock_preference('UseRecalls', 1);
139
    my $recall = Koha::Recall->new({
140
        biblionumber => $item->biblionumber,
141
        itemnumber => $item->itemnumber,
142
        item_level_recall => 1,
143
        borrowernumber => $patron->borrowernumber,
144
        branchcode => $library->branchcode,
145
        status => 'R',
146
    })->store;
147
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
148
    is( $dotransfer, 0, 'Do not transfer recalled item, it has already arrived' );
149
    is( $messages->{RecallPlacedAtHoldingBranch}, 1, "We found the recall");
150
151
    my $item2 = $builder->build_object({ class => 'Koha::Items' }); # this item will have a different holding branch to the pickup branch
152
    $recall = Koha::Recall->new({
153
        biblionumber => $item2->biblionumber,
154
        itemnumber => $item2->itemnumber,
155
        item_level_recall => 1,
156
        borrowernumber => $patron->borrowernumber,
157
        branchcode => $library->branchcode,
158
        status => 'R',
159
    })->store;
160
    ( $recall, $dotransfer, $messages ) = $recall->start_transfer;
161
    is( $dotransfer, 1, 'Transfer of recalled item succeeded' );
162
    is( $messages->{RecallFound}->recall_id, $recall->recall_id, "We found the recall");
133
};
163
};
134
164
135
subtest 'transfer an issued item' => sub {
165
subtest 'transfer an issued item' => sub {
Lines 230-232 subtest 'ignore_reserves flag' => sub { Link Here
230
    isnt( $messages->{ResFound}->{ResFound}, 'Reserved', "We did not return that we found a reserve");
260
    isnt( $messages->{ResFound}->{ResFound}, 'Reserved', "We did not return that we found a reserve");
231
    isnt( $messages->{ResFound}->{itemnumber}, $item->itemnumber, "We did not return the reserve info");
261
    isnt( $messages->{ResFound}->{itemnumber}, $item->itemnumber, "We did not return the reserve info");
232
};
262
};
263
264
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Holds.t (-1 / +29 lines)
Lines 7-13 use t::lib::TestBuilder; Link Here
7
7
8
use C4::Context;
8
use C4::Context;
9
9
10
use Test::More tests => 66;
10
use Test::More tests => 67;
11
use MARC::Record;
11
use MARC::Record;
12
12
13
use C4::Biblio;
13
use C4::Biblio;
Lines 1251-1253 subtest 'CanItemBeReserved / pickup_not_in_hold_group' => sub { Link Here
1251
1251
1252
    $schema->storage->txn_rollback;
1252
    $schema->storage->txn_rollback;
1253
};
1253
};
1254
1255
subtest 'CanItemBeReserved / recall' => sub {
1256
    plan tests => 1;
1257
1258
    $schema->storage->txn_begin;
1259
1260
    my $itemtype1 = $builder->build_object( { class => 'Koha::ItemTypes' } );
1261
    my $library1  = $builder->build_object( { class => 'Koha::Libraries', value => {pickup_location => 1} } );
1262
    my $patron1   = $builder->build_object( { class => 'Koha::Patrons', value => {branchcode => $library1->branchcode} } );
1263
    my $biblio1 = $builder->build_sample_biblio({ itemtype => $itemtype1->itemtype });
1264
    my $item1   = $builder->build_sample_item(
1265
        {
1266
            biblionumber => $biblio1->biblionumber,
1267
            library      => $library1->branchcode
1268
        }
1269
    );
1270
    Koha::Recall->new({
1271
        borrowernumber => $patron1->borrowernumber,
1272
        biblionumber => $biblio1->biblionumber,
1273
        branchcode => $library1->branchcode,
1274
        itemnumber => $item1->itemnumber,
1275
        recalldate => '2020-05-04 10:10:10',
1276
        item_level_recall => 1,
1277
    })->store;
1278
    is( CanItemBeReserved( $patron1->borrowernumber, $item1->itemnumber, $library1->branchcode )->{status}, 'recall', "Can't reserve an item that they have already recalled" );
1279
1280
    $schema->storage->txn_rollback;
1281
};
(-)a/t/db_dependent/Koha/Biblio.t (-2 / +118 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 12;
20
use Test::More tests => 13;
21
21
22
use C4::Biblio;
22
use C4::Biblio;
23
use Koha::Database;
23
use Koha::Database;
Lines 184-194 subtest 'pickup_locations' => sub { Link Here
184
184
185
    # Cleanup database
185
    # Cleanup database
186
    Koha::Holds->search->delete;
186
    Koha::Holds->search->delete;
187
    $dbh->do('DELETE FROM issues');
187
    Koha::Patrons->search->delete;
188
    Koha::Patrons->search->delete;
188
    Koha::Items->search->delete;
189
    Koha::Items->search->delete;
189
    Koha::Libraries->search->delete;
190
    Koha::Libraries->search->delete;
190
    Koha::CirculationRules->search->delete;
191
    Koha::CirculationRules->search->delete;
191
    $dbh->do('DELETE FROM issues');
192
    Koha::CirculationRules->set_rules(
192
    Koha::CirculationRules->set_rules(
193
        {
193
        {
194
            categorycode => undef,
194
            categorycode => undef,
Lines 549-551 subtest 'subscriptions() tests' => sub { Link Here
549
549
550
    $schema->storage->txn_rollback;
550
    $schema->storage->txn_rollback;
551
};
551
};
552
553
subtest 'Recalls tests' => sub {
554
555
    plan tests => 12;
556
557
    $schema->storage->txn_begin;
558
    my $item1 = $builder->build_sample_item;
559
    my $biblio = $item1->biblio;
560
    my $branchcode = $item1->holdingbranch;
561
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
562
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
563
    my $patron3 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
564
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype } });
565
    t::lib::Mocks::mock_userenv({ patron => $patron1 });
566
567
    my $recall1 = Koha::Recall->new({
568
        borrowernumber => $patron1->borrowernumber,
569
        recalldate => Koha::DateUtils::dt_from_string,
570
        biblionumber => $biblio->biblionumber,
571
        branchcode => $branchcode,
572
        status => 'R',
573
        itemnumber => $item1->itemnumber,
574
        expirationdate => undef,
575
        item_level_recall => 1
576
    })->store;
577
    my $recall2 = Koha::Recall->new({
578
        borrowernumber => $patron2->borrowernumber,
579
        recalldate => Koha::DateUtils::dt_from_string,
580
        biblionumber => $biblio->biblionumber,
581
        branchcode => $branchcode,
582
        status => 'R',
583
        itemnumber => undef,
584
        expirationdate => undef,
585
        item_level_recall => 0
586
    })->store;
587
    my $recall3 = Koha::Recall->new({
588
        borrowernumber => $patron3->borrowernumber,
589
        recalldate => Koha::DateUtils::dt_from_string,
590
        biblionumber => $biblio->biblionumber,
591
        branchcode => $branchcode,
592
        status => 'R',
593
        itemnumber => $item1->itemnumber,
594
        expirationdate => undef,
595
        item_level_recall => 1
596
    })->store;
597
598
    my $recalls_count = scalar $biblio->recalls;
599
    is( $recalls_count, 3, 'Correctly get number of active recalls for biblio' );
600
601
    $recall1->set_cancelled;
602
    $recall2->set_expired({ interface => 'COMMANDLINE' });
603
604
    $recalls_count = scalar $biblio->recalls;
605
    is( $recalls_count, 1, 'Correctly get number of active recalls for biblio' );
606
607
    t::lib::Mocks::mock_preference('UseRecalls', 0);
608
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall with UseRecalls disabled" );
609
610
    t::lib::Mocks::mock_preference("UseRecalls", 1);
611
    $item1->update({ notforloan => 1 });
612
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall with no available items" );
613
614
    $item1->update({ notforloan => 0 });
615
    Koha::CirculationRules->set_rules({
616
        branchcode => $branchcode,
617
        categorycode => $patron1->categorycode,
618
        itemtype => $item1->effective_itemtype,
619
        rules => {
620
            recalls_allowed => 0,
621
            recalls_per_record => 1,
622
            on_shelf_recalls => 'all',
623
        },
624
    });
625
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if recalls_allowed = 0" );
626
627
    Koha::CirculationRules->set_rules({
628
        branchcode => $branchcode,
629
        categorycode => $patron1->categorycode,
630
        itemtype => $item1->effective_itemtype,
631
        rules => {
632
            recalls_allowed => 1,
633
            recalls_per_record => 1,
634
            on_shelf_recalls => 'all',
635
        },
636
    });
637
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has more existing recall(s) than recalls_allowed" );
638
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has more existing recall(s) than recalls_per_record" );
639
640
    $recall1->set_cancelled;
641
    C4::Circulation::AddIssue( $patron1->unblessed, $item2->barcode );
642
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has already checked out an item attached to this biblio" );
643
644
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if on_shelf_recalls = all and items are still available" );
645
646
    Koha::CirculationRules->set_rules({
647
        branchcode => $branchcode,
648
        categorycode => $patron1->categorycode,
649
        itemtype => $item1->effective_itemtype,
650
        rules => {
651
            recalls_allowed => 1,
652
            recalls_per_record => 1,
653
            on_shelf_recalls => 'any',
654
        },
655
    });
656
    C4::Circulation::AddReturn( $item2->barcode, $branchcode );
657
    is( $biblio->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if no items are checked out" );
658
659
    $recall2->set_cancelled;
660
    C4::Circulation::AddIssue( $patron2->unblessed, $item2->barcode );
661
    is( $biblio->can_be_recalled({ patron => $patron1 }), 2, "Can recall two items" );
662
663
    $item1->update({ withdrawn => 1 });
664
    is( $biblio->can_be_recalled({ patron => $patron1 }), 1, "Can recall one item" );
665
666
    $schema->storage->txn_rollback;
667
};
(-)a/t/db_dependent/Koha/Item.t (-1 / +188 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 6;
22
use Test::More tests => 7;
23
23
24
use C4::Biblio;
24
use C4::Biblio;
25
use C4::Circulation;
25
use C4::Circulation;
Lines 501-503 subtest 'renewal_branchcode' => sub { Link Here
501
    is( $item->renewal_branchcode({branch=>'MANATEE'}), $item->homebranch, "If interface opac and OpacRenewalBranch set to itemhomebranch, we get homebranch of item even if branch passed");
501
    is( $item->renewal_branchcode({branch=>'MANATEE'}), $item->homebranch, "If interface opac and OpacRenewalBranch set to itemhomebranch, we get homebranch of item even if branch passed");
502
502
503
};
503
};
504
505
subtest 'Recalls tests' => sub {
506
507
    plan tests => 20;
508
509
    $schema->storage->txn_begin;
510
511
    my $item1 = $builder->build_sample_item;
512
    my $biblio = $item1->biblio;
513
    my $branchcode = $item1->holdingbranch;
514
    my $patron1 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
515
    my $patron2 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
516
    my $patron3 = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $branchcode } });
517
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { holdingbranch => $branchcode, homebranch => $branchcode, biblionumber => $biblio->biblionumber, itype => $item1->effective_itemtype } });
518
    t::lib::Mocks::mock_userenv({ patron => $patron1 });
519
520
    my $recall1 = Koha::Recall->new({
521
        borrowernumber => $patron1->borrowernumber,
522
        recalldate => Koha::DateUtils::dt_from_string,
523
        biblionumber => $biblio->biblionumber,
524
        branchcode => $branchcode,
525
        status => 'R',
526
        itemnumber => $item1->itemnumber,
527
        expirationdate => undef,
528
        item_level_recall => 1
529
    })->store;
530
    my $recall2 = Koha::Recall->new({
531
        borrowernumber => $patron2->borrowernumber,
532
        recalldate => Koha::DateUtils::dt_from_string,
533
        biblionumber => $biblio->biblionumber,
534
        branchcode => $branchcode,
535
        status => 'R',
536
        itemnumber => $item1->itemnumber,
537
        expirationdate => undef,
538
        item_level_recall =>1
539
    })->store;
540
541
    is( $item1->recall->borrowernumber, $patron1->borrowernumber, 'Correctly returns most relevant recall' );
542
543
    $recall2->set_cancelled;
544
545
    t::lib::Mocks::mock_preference('UseRecalls', 0);
546
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall with UseRecalls disabled" );
547
548
    t::lib::Mocks::mock_preference("UseRecalls", 1);
549
550
    $item1->update({ notforloan => 1 });
551
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall that is not for loan" );
552
    $item1->update({ notforloan => 0, itemlost => 1 });
553
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall that is marked lost" );
554
    $item1->update({ itemlost => 0, withdrawn => 1 });
555
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall that is withdrawn" );
556
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall item if not checked out" );
557
558
    $item1->update({ withdrawn => 0 });
559
    C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
560
561
    Koha::CirculationRules->set_rules({
562
        branchcode => $branchcode,
563
        categorycode => $patron1->categorycode,
564
        itemtype => $item1->effective_itemtype,
565
        rules => {
566
            recalls_allowed => 0,
567
            recalls_per_record => 1,
568
            on_shelf_recalls => 'all',
569
        },
570
    });
571
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if recalls_allowed = 0" );
572
573
    Koha::CirculationRules->set_rules({
574
        branchcode => $branchcode,
575
        categorycode => $patron1->categorycode,
576
        itemtype => $item1->effective_itemtype,
577
        rules => {
578
            recalls_allowed => 1,
579
            recalls_per_record => 1,
580
            on_shelf_recalls => 'all',
581
        },
582
    });
583
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has more existing recall(s) than recalls_allowed" );
584
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has more existing recall(s) than recalls_per_record" );
585
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if patron has already recalled this item" );
586
587
    my $reserve_id = C4::Reserves::AddReserve({ branchcode => $branchcode, borrowernumber => $patron1->borrowernumber, biblionumber => $item1->biblionumber, itemnumber => $item1->itemnumber });
588
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall item if patron has already reserved it" );
589
    C4::Reserves::ModReserve({ rank => 'del', reserve_id => $reserve_id, branchcode => $branchcode, itemnumber => $item1->itemnumber, borrowernumber => $patron1->borrowernumber, biblionumber => $item1->biblionumber });
590
591
    $recall1->set_cancelled;
592
    is( $item1->can_be_recalled({ patron => $patron2 }), 0, "Can't recall if patron has already checked out an item attached to this biblio" );
593
594
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if on_shelf_recalls = all and items are still available" );
595
596
    Koha::CirculationRules->set_rules({
597
        branchcode => $branchcode,
598
        categorycode => $patron1->categorycode,
599
        itemtype => $item1->effective_itemtype,
600
        rules => {
601
            recalls_allowed => 1,
602
            recalls_per_record => 1,
603
            on_shelf_recalls => 'any',
604
        },
605
    });
606
    C4::Circulation::AddReturn( $item1->barcode, $branchcode );
607
    is( $item1->can_be_recalled({ patron => $patron1 }), 0, "Can't recall if no items are checked out" );
608
609
    C4::Circulation::AddIssue( $patron2->unblessed, $item1->barcode );
610
    is( $item1->can_be_recalled({ patron => $patron1 }), 1, "Can recall item" );
611
612
    $recall1 = Koha::Recall->new({
613
        borrowernumber => $patron1->borrowernumber,
614
        recalldate => Koha::DateUtils::dt_from_string,
615
        biblionumber => $biblio->biblionumber,
616
        branchcode => $branchcode,
617
        status => 'R',
618
        itemnumber => undef,
619
        expirationdate => undef,
620
        item_level_recall => 0
621
    })->store;
622
623
    # Patron2 has Item1 checked out. Patron1 has placed a biblio-level recall on Biblio1, so check if Item1 can fulfill Patron1's recall.
624
625
    Koha::CirculationRules->set_rules({
626
        branchcode => undef,
627
        categorycode => undef,
628
        itemtype => $item1->effective_itemtype,
629
        rules => {
630
            recalls_allowed => 0,
631
            recalls_per_record => 1,
632
            on_shelf_recalls => 'any',
633
        },
634
    });
635
    is( $item1->can_be_waiting_recall, 0, "Recalls not allowed for this itemtype" );
636
637
    Koha::CirculationRules->set_rules({
638
        branchcode => undef,
639
        categorycode => undef,
640
        itemtype => $item1->effective_itemtype,
641
        rules => {
642
            recalls_allowed => 1,
643
            recalls_per_record => 1,
644
            on_shelf_recalls => 'any',
645
        },
646
    });
647
    is( $item1->can_be_waiting_recall, 1, "Recalls are allowed for this itemtype" );
648
649
    # check_recalls tests
650
651
    $recall1 = Koha::Recall->new({
652
        borrowernumber => $patron2->borrowernumber,
653
        recalldate => Koha::DateUtils::dt_from_string,
654
        biblionumber => $biblio->biblionumber,
655
        branchcode => $branchcode,
656
        status => 'R',
657
        itemnumber => $item1->itemnumber,
658
        expirationdate => undef,
659
        item_level_recall => 1
660
    })->store;
661
    $recall2 = Koha::Recall->new({
662
        borrowernumber => $patron1->borrowernumber,
663
        recalldate => Koha::DateUtils::dt_from_string,
664
        biblionumber => $biblio->biblionumber,
665
        branchcode => $branchcode,
666
        status => 'R',
667
        itemnumber => undef,
668
        expirationdate => undef,
669
        item_level_recall => 0
670
    })->store;
671
    $recall2->set_waiting({ item => $item1 });
672
673
    # return a waiting recall
674
    my $check_recall = $item1->check_recalls;
675
    is( $check_recall->borrowernumber, $patron1->borrowernumber, "Waiting recall is highest priority and returned" );
676
677
    $recall2->revert_waiting;
678
679
    # return an item-level recall
680
    $check_recall = $item1->check_recalls;
681
    is( $check_recall->borrowernumber, $patron2->borrowernumber, "No waiting recall, so oldest item-level recall is returned" );
682
683
    $recall1->set_cancelled;
684
685
    # return a biblio-level recall
686
    $check_recall = $item1->check_recalls;
687
    is( $check_recall->borrowernumber, $patron1->borrowernumber, "No item-level recalls so oldest biblio-level recall is returned" );
688
689
    $recall2->set_cancelled;
690
};
(-)a/t/db_dependent/Koha/Patron.t (-1 / +57 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 4;
22
use Test::More tests => 5;
23
use Test::Exception;
23
use Test::Exception;
24
24
25
use Koha::Database;
25
use Koha::Database;
Lines 211-213 subtest 'login_attempts tests' => sub { Link Here
211
211
212
    $schema->storage->txn_rollback;
212
    $schema->storage->txn_rollback;
213
};
213
};
214
215
subtest 'recalls() tests' => sub {
216
217
    plan tests => 2;
218
219
    $schema->storage->txn_begin;
220
221
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
222
    my $biblio1 = $builder->build_object({ class => 'Koha::Biblios' });
223
    my $item1 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio1->biblionumber } });
224
    my $biblio2 = $builder->build_object({ class => 'Koha::Biblios' });
225
    my $item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio2->biblionumber } });
226
227
    Koha::Recall->new({
228
        biblionumber => $biblio1->biblionumber,
229
        borrowernumber => $patron->borrowernumber,
230
        itemnumber => $item1->itemnumber,
231
        branchcode => $patron->branchcode,
232
        recalldate => dt_from_string,
233
        status => 'R',
234
        item_level_recall => 1,
235
    })->store;
236
    Koha::Recall->new({
237
        biblionumber => $biblio2->biblionumber,
238
        borrowernumber => $patron->borrowernumber,
239
        itemnumber => $item2->itemnumber,
240
        branchcode => $patron->branchcode,
241
        recalldate => dt_from_string,
242
        status => 'R',
243
        item_level_recall => 1,
244
    })->store;
245
    Koha::Recall->new({
246
        biblionumber => $biblio1->biblionumber,
247
        borrowernumber => $patron->borrowernumber,
248
        itemnumber => undef,
249
        branchcode => $patron->branchcode,
250
        recalldate => dt_from_string,
251
        status => 'R',
252
        item_level_recall => 0,
253
    })->store;
254
    my $recall = Koha::Recall->new({
255
        biblionumber => $biblio1->biblionumber,
256
        borrowernumber => $patron->borrowernumber,
257
        itemnumber => undef,
258
        branchcode => $patron->branchcode,
259
        recalldate => dt_from_string,
260
        status => 'R',
261
        item_level_recall => 0,
262
    })->store;
263
    $recall->set_cancelled;
264
265
    is( $patron->recalls->count, 3, "Correctly gets this patron's active recalls" );
266
    is( $patron->recalls({ biblionumber => $biblio1->biblionumber })->count, 2, "Correctly gets this patron's active recalls on a specific biblio" );
267
268
    $schema->storage->txn_rollback;
269
};
(-)a/t/db_dependent/Stats.t (-1 / +1 lines)
Lines 55-61 $return_error = $@; Link Here
55
isnt ($return_error,'',"UpdateStats returns undef and croaks if type is undef");
55
isnt ($return_error,'',"UpdateStats returns undef and croaks if type is undef");
56
56
57
# returns undef and croaks if mandatory params are missing
57
# returns undef and croaks if mandatory params are missing
58
my @allowed_circulation_types = qw (renew issue localuse return);
58
my @allowed_circulation_types = qw (renew issue localuse return onsite_checkout recall);
59
my @allowed_accounts_types = qw (writeoff payment);
59
my @allowed_accounts_types = qw (writeoff payment);
60
my @circulation_mandatory_keys = qw (branch borrowernumber itemnumber ccode itemtype); #don't check type here
60
my @circulation_mandatory_keys = qw (branch borrowernumber itemnumber ccode itemtype); #don't check type here
61
my @accounts_mandatory_keys = qw (branch borrowernumber amount); #don't check type here
61
my @accounts_mandatory_keys = qw (branch borrowernumber amount); #don't check type here
(-)a/t/db_dependent/XSLT.t (-3 / +12 lines)
Lines 34-40 my $builder = t::lib::TestBuilder->new; Link Here
34
$schema->storage->txn_begin;
34
$schema->storage->txn_begin;
35
35
36
subtest 'buildKohaItemsNamespace status tests' => sub {
36
subtest 'buildKohaItemsNamespace status tests' => sub {
37
    plan tests => 13;
37
    plan tests => 14;
38
    my $itype = $builder->build_object({ class => 'Koha::ItemTypes' });
38
    my $itype = $builder->build_object({ class => 'Koha::ItemTypes' });
39
    my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' });
39
    my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' });
40
    my $item  = $builder->build_sample_item({ itype => $itype->itemtype });
40
    my $item  = $builder->build_sample_item({ itype => $itype->itemtype });
Lines 103-109 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
103
        }
103
        }
104
    });
104
    });
105
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
105
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
106
    like($xml,qr{<status>Waiting</status>},"Waiting status takes precedence over In transit");
106
    like($xml,qr{<status>Waiting</status>},"Waiting status takes precedence over In transit (holds)");
107
    $hold->cancel;
107
108
108
    $builder->build({ source => "TmpHoldsqueue", value => {
109
    $builder->build({ source => "TmpHoldsqueue", value => {
109
        itemnumber => $item->itemnumber
110
        itemnumber => $item->itemnumber
Lines 112-117 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
112
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
113
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
113
    like($xml,qr{<status>Pending hold</status>},"Pending status takes precedence over all");
114
    like($xml,qr{<status>Pending hold</status>},"Pending status takes precedence over all");
114
115
116
    my $recall = $builder->build_object({ class => 'Koha::Recalls', value => {
117
        biblionumber    => $item->biblionumber,
118
        itemnumber      => $item->itemnumber,
119
        branchcode      => $item->holdingbranch,
120
        status          => 'R',
121
    }});
122
    $recall->set_waiting;
123
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
124
    like($xml,qr{<status>Waiting</status>},"Waiting status takes precedence over In transit (recalls)");
115
125
116
};
126
};
117
127
118
- 

Return to bug 19532