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

(-)a/C4/Circulation.pm (-136 / +42 lines)
Lines 1545-1595 sub AddIssue { Link Here
1545
            $item_object->store({log_action => 0});
1545
            $item_object->store({log_action => 0});
1546
            ModDateLastSeen( $item_object->itemnumber );
1546
            ModDateLastSeen( $item_object->itemnumber );
1547
1547
1548
            # If the item was lost, it has now been found, restore/charge the overdue if necessary
1548
            # If the item was lost, it has now been found, charge the overdue if necessary
1549
            if ($was_lost) {
1549
            if ($was_lost) {
1550
                my $lostreturn_policy =
1550
                if ( $item_object->{_charge} ) {
1551
                  Koha::CirculationRules->get_lostreturn_policy(
1551
                    $actualissue //= Koha::Old::Checkouts->search(
1552
                    {
1552
                        { itemnumber => $item_unblessed->{itemnumber} },
1553
                        return_branch => C4::Context->userenv->{branch},
1553
                        {
1554
                        item          => $item_object
1554
                            order_by => { '-desc' => 'returndate' },
1555
                    }
1555
                            rows     => 1
1556
                  );
1557
1558
                if ($lostreturn_policy) {
1559
1560
                    if ( $lostreturn_policy eq 'charge' ) {
1561
                        $actualissue //= Koha::Old::Checkouts->search(
1562
                            { itemnumber => $item_unblessed->{itemnumber} },
1563
                            {
1564
                                order_by => { '-desc' => 'returndate' },
1565
                                rows     => 1
1566
                            }
1567
                        )->single;
1568
                        unless ( exists( $borrower->{branchcode} ) ) {
1569
                            my $patron = $actualissue->patron;
1570
                            $borrower = $patron->unblessed;
1571
                        }
1556
                        }
1572
                        _CalculateAndUpdateFine(
1557
                    )->single;
1573
                            {
1558
                    unless ( exists( $borrower->{branchcode} ) ) {
1574
                                issue       => $actualissue,
1559
                        my $patron = $actualissue->patron;
1575
                                item        => $item_unblessed,
1560
                        $borrower = $patron->unblessed;
1576
                                borrower    => $borrower,
1577
                                return_date => $issuedate
1578
                            }
1579
                        );
1580
                        _FixOverduesOnReturn( $borrower->{borrowernumber},
1581
                            $item_object->itemnumber, undef, 'RENEWED' );
1582
                    }
1583
                    elsif ( $lostreturn_policy eq 'restore' ) {
1584
                        _RestoreOverdueForLostAndFound(
1585
                            $item_object->itemnumber );
1586
                    }
1587
1588
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
1589
                        $account->reconcile_balance;
1590
                    }
1561
                    }
1562
                    _CalculateAndUpdateFine(
1563
                        {
1564
                            issue       => $actualissue,
1565
                            item        => $item_unblessed,
1566
                            borrower    => $borrower,
1567
                            return_date => $issuedate
1568
                        }
1569
                    );
1570
                    _FixOverduesOnReturn( $borrower->{borrowernumber},
1571
                        $item_object->itemnumber, undef, 'RENEWED' );
1591
                }
1572
                }
1592
1593
            }
1573
            }
1594
1574
1595
            # If it costs to borrow this book, charge it to the patron's account.
1575
            # If it costs to borrow this book, charge it to the patron's account.
Lines 2093-2138 sub AddReturn { Link Here
2093
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2073
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2094
2074
2095
    # fix up the accounts.....
2075
    # fix up the accounts.....
2096
    if ( $item_was_lost ) {
2076
    if ($item_was_lost) {
2097
        $messages->{'WasLost'} = 1;
2077
        $messages->{'WasLost'} = 1;
2098
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2078
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2099
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2079
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2100
2080
            $messages->{'LostItemFeeRestored'} = $updated_item->{_restored};
2101
            my $lostreturn_policy =
2081
2102
              Koha::CirculationRules->get_lostreturn_policy(
2082
            if ( $updated_item->{_charge} ) {
2103
                {
2083
                $issue //= Koha::Old::Checkouts->search(
2104
                    return_branch => C4::Context->userenv->{branch},
2084
                    { itemnumber => $item->itemnumber },
2105
                    item          => $updated_item
2085
                    { order_by   => { '-desc' => 'returndate' }, rows => 1 } )
2086
                  ->single;
2087
                unless ( exists( $patron_unblessed->{branchcode} ) ) {
2088
                    my $patron = $issue->patron;
2089
                    $patron_unblessed = $patron->unblessed;
2106
                }
2090
                }
2107
              );
2091
                _CalculateAndUpdateFine(
2108
2092
                    {
2109
            if ($lostreturn_policy) {
2093
                        issue       => $issue,
2110
2094
                        item        => $item->unblessed,
2111
                if ( $lostreturn_policy eq 'charge' ) {
2095
                        borrower    => $patron_unblessed,
2112
                    $issue //= Koha::Old::Checkouts->search(
2096
                        return_date => $return_date
2113
                        { itemnumber => $item->itemnumber },
2114
                        { order_by   => { '-desc' => 'returndate' }, rows => 1 }
2115
                    )->single;
2116
                    unless (exists($patron_unblessed->{branchcode})) {
2117
                        my $patron = $issue->patron;
2118
                        $patron_unblessed = $patron->unblessed;
2119
                    }
2097
                    }
2120
                    _CalculateAndUpdateFine(
2098
                );
2121
                        {
2099
                _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2122
                            issue       => $issue,
2100
                    $item->itemnumber, undef, 'RETURNED' );
2123
                            item        => $item->unblessed,
2101
                $messages->{'LostItemFeeCharged'} = 1;
2124
                            borrower    => $patron_unblessed,
2125
                            return_date => $return_date
2126
                        }
2127
                    );
2128
                    _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2129
                        $item->itemnumber, undef, 'RETURNED' );
2130
                    $messages->{'LostItemFeeCharged'} = 1;
2131
                }
2132
                elsif ( $lostreturn_policy eq 'restore' ) {
2133
                    _RestoreOverdueForLostAndFound( $item->itemnumber );
2134
                    $messages->{'LostItemFeeRestored'} = 1;
2135
                }
2136
            }
2102
            }
2137
        }
2103
        }
2138
    }
2104
    }
Lines 2587-2652 sub _FixOverduesOnReturn { Link Here
2587
    return $result;
2553
    return $result;
2588
}
2554
}
2589
2555
2590
=head2 _RestoreOverdueForLostAndFound
2591
2592
   &_RestoreOverdueForLostAndFound( $itemnumber );
2593
2594
C<$itemnumber> itemnumber
2595
2596
Internal function
2597
2598
=cut
2599
2600
sub _RestoreOverdueForLostAndFound {
2601
    my ( $item ) = @_;
2602
2603
    unless( $item ) {
2604
        warn "_RestoreOverdueForLostAndFound() not supplied valid itemnumber";
2605
        return;
2606
    }
2607
2608
    my $schema = Koha::Database->schema;
2609
2610
    my $result = $schema->txn_do(
2611
        sub {
2612
            # check for lost overdue fine
2613
            my $accountlines = Koha::Account::Lines->search(
2614
                {
2615
                    itemnumber      => $item,
2616
                    debit_type_code => 'OVERDUE',
2617
                    status          => 'LOST'
2618
                },
2619
                {
2620
                    order_by => { '-desc' => 'date' },
2621
                    rows     => 1
2622
                }
2623
            );
2624
            return 0 unless $accountlines->count; # no warning, there's just nothing to fix
2625
2626
            # Update status of fine
2627
            my $overdue = $accountlines->next;
2628
            $overdue->status('RETURNED')->store();
2629
2630
            # Find related forgive credit
2631
            my $refunds = $overdue->credits(
2632
                {
2633
                    credit_type_code => 'FORGIVEN',
2634
                    itemnumber       => $item,
2635
                    status           => [ { '!=' => 'VOID' }, undef ]
2636
                },
2637
                { order_by => { '-desc' => 'date' }, rows => 1 }
2638
            );
2639
            return 0 unless $refunds->count; # no warning, there's just nothing to fix
2640
2641
            # Revert the forgive credit
2642
            my $refund = $refunds->next;
2643
            return $refund->void();
2644
        }
2645
    );
2646
2647
    return $result;
2648
}
2649
2650
=head2 _GetCircControlBranch
2556
=head2 _GetCircControlBranch
2651
2557
2652
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
2558
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
(-)a/Koha/Item.pm (-71 / +120 lines)
Lines 823-830 sub _set_found_trigger { Link Here
823
        return $self unless $lost_age_in_days < $no_refund_after_days;
823
        return $self unless $lost_age_in_days < $no_refund_after_days;
824
    }
824
    }
825
825
826
    return $self
826
    my $lostreturn_policy = Koha::CirculationRules->get_lostreturn_policy(
827
      unless Koha::CirculationRules->get_lostreturn_policy(
828
        {
827
        {
829
            item          => $self,
828
            item          => $self,
830
            return_branch => C4::Context->userenv
829
            return_branch => C4::Context->userenv
Lines 833-912 sub _set_found_trigger { Link Here
833
        }
832
        }
834
      );
833
      );
835
834
836
    # check for charge made for lost book
835
    if ( $lostreturn_policy ) {
837
    my $accountlines = Koha::Account::Lines->search(
838
        {
839
            itemnumber      => $self->itemnumber,
840
            debit_type_code => 'LOST',
841
            status          => [ undef, { '<>' => 'FOUND' } ]
842
        },
843
        {
844
            order_by => { -desc => [ 'date', 'accountlines_id' ] }
845
        }
846
    );
847
848
    return $self unless $accountlines->count > 0;
849
850
    my $accountline     = $accountlines->next;
851
    my $total_to_refund = 0;
852
836
853
    return $self unless $accountline->borrowernumber;
837
        # refund charge made for lost book
854
838
        my $lost_charge = Koha::Account::Lines->search(
855
    my $patron = Koha::Patrons->find( $accountline->borrowernumber );
856
    return $self
857
      unless $patron;  # Patron has been deleted, nobody to credit the return to
858
                       # FIXME Should not we notify this somewhere
859
860
    my $account = $patron->account;
861
862
    # Use cases
863
    if ( $accountline->amount > $accountline->amountoutstanding ) {
864
865
    # some amount has been cancelled. collect the offsets that are not writeoffs
866
    # this works because the only way to subtract from this kind of a debt is
867
    # using the UI buttons 'Pay' and 'Write off'
868
        my $credits_offsets = Koha::Account::Offsets->search(
869
            {
839
            {
870
                debit_id  => $accountline->id,
840
                itemnumber      => $self->itemnumber,
871
                credit_id => { '!=' => undef },     # it is not the debit itself
841
                debit_type_code => 'LOST',
872
                type      => { '!=' => 'Writeoff' },
842
                status          => [ undef, { '<>' => 'FOUND' } ]
873
                amount => { '<' => 0 }    # credits are negative on the DB
843
            },
874
            }
875
        );
876
877
        $total_to_refund = ( $credits_offsets->count > 0 )
878
          ? $credits_offsets->total * -1    # credits are negative on the DB
879
          : 0;
880
    }
881
882
    my $credit_total = $accountline->amountoutstanding + $total_to_refund;
883
884
    my $credit;
885
    if ( $credit_total > 0 ) {
886
        my $branchcode =
887
          C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
888
        $credit = $account->add_credit(
889
            {
844
            {
890
                amount      => $credit_total,
845
                order_by => { -desc => [ 'date', 'accountlines_id' ] },
891
                description => 'Item found ' . $self->itemnumber,
846
                rows     => 1
892
                type        => 'LOST_FOUND',
893
                interface   => C4::Context->interface,
894
                library_id  => $branchcode,
895
                item_id     => $self->itemnumber,
896
                issue_id    => $accountline->issue_id
897
            }
847
            }
898
        );
848
        )->single;
899
849
900
        $credit->apply( { debits => [$accountline] } );
850
        if ( $lost_charge ) {
901
        $self->{_refunded} = 1;
851
902
    }
852
            my $patron = $lost_charge->patron;
903
853
            if ( $patron ) {
904
    # Update the account status
854
905
    $accountline->status('FOUND');
855
                my $account = $patron->account;
906
    $accountline->store();
856
                my $total_to_refund = 0;
857
858
                # Use cases
859
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
860
861
                    # some amount has been cancelled. collect the offsets that are not writeoffs
862
                    # this works because the only way to subtract from this kind of a debt is
863
                    # using the UI buttons 'Pay' and 'Write off'
864
                    my $credits_offsets = Koha::Account::Offsets->search(
865
                        {
866
                            debit_id  => $lost_charge->id,
867
                            credit_id => { '!=' => undef },     # it is not the debit itself
868
                            type      => { '!=' => 'Writeoff' },
869
                            amount    => { '<' => 0 }    # credits are negative on the DB
870
                        }
871
                    );
872
873
                    $total_to_refund = ( $credits_offsets->count > 0 )
874
                      ? $credits_offsets->total * -1    # credits are negative on the DB
875
                      : 0;
876
                }
877
878
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
879
880
                my $credit;
881
                if ( $credit_total > 0 ) {
882
                    my $branchcode =
883
                      C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
884
                    $credit = $account->add_credit(
885
                        {
886
                            amount      => $credit_total,
887
                            description => 'Item found ' . $self->itemnumber,
888
                            type        => 'LOST_FOUND',
889
                            interface   => C4::Context->interface,
890
                            library_id  => $branchcode,
891
                            item_id     => $self->itemnumber,
892
                            issue_id    => $lost_charge->issue_id
893
                        }
894
                    );
895
896
                    $credit->apply( { debits => [$lost_charge] } );
897
                    $self->{_refunded} = 1;
898
                }
899
900
                # Update the account status
901
                $lost_charge->status('FOUND');
902
                $lost_charge->store();
903
904
                # Reconcile balances if required
905
                if ( C4::Context->preference('AccountAutoReconcile') ) {
906
                    $account->reconcile_balance;
907
                }
908
            }
909
        }
907
910
908
    if ( defined $account and C4::Context->preference('AccountAutoReconcile') ) {
911
        # restore fine for lost book
909
        $account->reconcile_balance;
912
        if ( $lostreturn_policy eq 'restore' ) {
913
            my $lost_overdue = Koha::Account::Lines->search(
914
                {
915
                    itemnumber      => $self->itemnumber,
916
                    debit_type_code => 'OVERDUE',
917
                    status          => 'LOST'
918
                },
919
                {
920
                    order_by => { '-desc' => 'date' },
921
                    rows     => 1
922
                }
923
            )->single;
924
925
            if ( $lost_overdue ) {
926
927
                my $patron = $lost_overdue->patron;
928
                if ($patron) {
929
                    my $account = $patron->account;
930
931
                    # Update status of fine
932
                    $lost_overdue->status('FOUND')->store();
933
934
                    # Find related forgive credit
935
                    my $refund = $lost_overdue->credits(
936
                        {
937
                            credit_type_code => 'FORGIVEN',
938
                            itemnumber       => $self->itemnumber,
939
                            status           => [ { '!=' => 'VOID' }, undef ]
940
                        },
941
                        { order_by => { '-desc' => 'date' }, rows => 1 }
942
                    )->single;
943
944
                    if ( $refund ) {
945
                        # Revert the forgive credit
946
                        $refund->void();
947
                        $self->{_restored} = 1;
948
                    }
949
950
                    # Reconcile balances if required
951
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
952
                        $account->reconcile_balance;
953
                    }
954
                }
955
            }
956
        } elsif ( $lostreturn_policy eq 'charge' ) {
957
            $self->{_charge} = 1;
958
        }
910
    }
959
    }
911
960
912
    return $self;
961
    return $self;
(-)a/t/db_dependent/Circulation.t (-65 lines)
Lines 2666-2736 subtest 'AddReturn | is_overdue' => sub { Link Here
2666
    };
2666
    };
2667
};
2667
};
2668
2668
2669
subtest '_RestoreOverdueForLostAndFound' => sub {
2670
2671
    plan tests => 7;
2672
2673
    my $manager = $builder->build_object( { class => "Koha::Patrons" } );
2674
    t::lib::Mocks::mock_userenv(
2675
        { patron => $manager, branchcode => $manager->branchcode } );
2676
2677
    my $patron = $builder->build_object( { class => "Koha::Patrons" } );
2678
    my $item = $builder->build_sample_item();
2679
2680
    # No fine found
2681
    my $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2682
    is($result, 0, "0 returned when no overdue found");
2683
2684
    # Fine not forgiven
2685
    my $account = $patron->account;
2686
    my $overdue = $account->add_debit(
2687
        {
2688
            amount     => 30.00,
2689
            user_id    => $manager->borrowernumber,
2690
            library_id => $library2->{branchcode},
2691
            interface  => 'test',
2692
            item_id    => $item->itemnumber,
2693
            type       => 'OVERDUE',
2694
        }
2695
    )->store();
2696
    $overdue->status('LOST')->store();
2697
2698
    $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2699
    is($result, 0, "0 returned when overdue found without forgival");
2700
    $overdue->discard_changes;
2701
    is($overdue->status, 'RETURNED', 'Overdue status updated to RETURNED');
2702
2703
    # Reset status
2704
    $overdue->status('LOST')->store();
2705
2706
    # Fine forgiven
2707
    my $credit = $account->add_credit(
2708
        {
2709
            amount     => 30.00,
2710
            user_id    => $manager->borrowernumber,
2711
            library_id => $library2->{branchcode},
2712
            interface  => 'test',
2713
            type       => 'FORGIVEN',
2714
            item_id    => $item->itemnumber
2715
        }
2716
    );
2717
    $credit->apply( { debits => [$overdue], offset_type => 'Forgiven' } );
2718
2719
    $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2720
2721
    is( ref($result), 'Koha::Account::Line', 'Return a Koha::Account::Line object on sucess');
2722
    $overdue->discard_changes;
2723
    is($overdue->status, 'RETURNED', 'Overdue status updated to RETURNED');
2724
    is($overdue->amountoutstanding, $overdue->amount, 'Overdue outstanding restored');
2725
2726
    # Missing parameters
2727
    warning_like {
2728
        C4::Circulation::_RestoreOverdueForLostAndFound( undef )
2729
    }
2730
    qr/_RestoreOverdueForLostAndFound\(\) not supplied valid itemnumber/,
2731
      "parameter warning received for missing itemnumbernumber";
2732
};
2733
2734
subtest '_FixOverduesOnReturn' => sub {
2669
subtest '_FixOverduesOnReturn' => sub {
2735
    plan tests => 14;
2670
    plan tests => 14;
2736
2671
(-)a/t/db_dependent/Koha/Items.t (-2 / +331 lines)
Lines 138-144 subtest 'store' => sub { Link Here
138
    };
138
    };
139
139
140
    subtest '_lost_found_trigger' => sub {
140
    subtest '_lost_found_trigger' => sub {
141
        plan tests => 7;
141
        plan tests => 10;
142
142
143
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
143
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
144
        t::lib::Mocks::mock_preference( 'WhenLostForgiveFine',          0 );
144
        t::lib::Mocks::mock_preference( 'WhenLostForgiveFine',          0 );
Lines 761-766 subtest 'store' => sub { Link Here
761
761
762
        };
762
        };
763
763
764
        subtest 'restore fine | no overdue' => sub {
765
766
            plan tests => 8;
767
768
            my $manager =
769
              $builder->build_object( { class => "Koha::Patrons" } );
770
            t::lib::Mocks::mock_userenv(
771
                { patron => $manager, branchcode => $manager->branchcode } );
772
773
            # Set lostreturn_policy to 'restore' for tests
774
            my $specific_rule_restore = $builder->build(
775
                {
776
                    source => 'CirculationRule',
777
                    value  => {
778
                        branchcode   => $manager->branchcode,
779
                        categorycode => undef,
780
                        itemtype     => undef,
781
                        rule_name    => 'lostreturn',
782
                        rule_value   => 'restore'
783
                    }
784
                }
785
            );
786
787
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
788
789
            my $item = $builder->build_sample_item(
790
                {
791
                    biblionumber     => $biblio->biblionumber,
792
                    library          => $library->branchcode,
793
                    replacementprice => $replacement_amount,
794
                    itype            => $item_type->itemtype
795
                }
796
            );
797
798
            my $issue =
799
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
800
801
            # Simulate item marked as lost
802
            $item->itemlost(1)->store;
803
            C4::Circulation::LostItem( $item->itemnumber, 1 );
804
805
            my $processing_fee_lines = Koha::Account::Lines->search(
806
                {
807
                    borrowernumber  => $patron->id,
808
                    itemnumber      => $item->itemnumber,
809
                    debit_type_code => 'PROCESSING'
810
                }
811
            );
812
            is( $processing_fee_lines->count,
813
                1, 'Only one processing fee produced' );
814
            my $processing_fee_line = $processing_fee_lines->next;
815
            is( $processing_fee_line->amount + 0,
816
                $processfee_amount,
817
                'The right PROCESSING amount is generated' );
818
            is( $processing_fee_line->amountoutstanding + 0,
819
                $processfee_amount,
820
                'The right PROCESSING amountoutstanding is generated' );
821
822
            my $lost_fee_lines = Koha::Account::Lines->search(
823
                {
824
                    borrowernumber  => $patron->id,
825
                    itemnumber      => $item->itemnumber,
826
                    debit_type_code => 'LOST'
827
                }
828
            );
829
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
830
            my $lost_fee_line = $lost_fee_lines->next;
831
            is( $lost_fee_line->amount + 0,
832
                $replacement_amount, 'The right LOST amount is generated' );
833
            is( $lost_fee_line->amountoutstanding + 0,
834
                $replacement_amount,
835
                'The right LOST amountountstanding is generated' );
836
837
            my $account = $patron->account;
838
            my $debts   = $account->outstanding_debits;
839
840
            # Pay off the debt
841
            my $credit = $account->add_credit(
842
                {
843
                    amount    => $account->balance,
844
                    type      => 'PAYMENT',
845
                    interface => 'test',
846
                }
847
            );
848
            $credit->apply(
849
                { debits => [ $debts->as_list ], offset_type => 'Payment' } );
850
851
            # Simulate item marked as found
852
            $item->itemlost(0)->store;
853
            is( $item->{_refunded}, 1, 'Refund triggered' );
854
            is( $item->{_restored}, undef, 'Restore not triggered when there is no overdue fine found' );
855
        };
856
857
        subtest 'restore fine | unforgiven overdue' => sub {
858
859
            plan tests => 10;
860
861
            # Set lostreturn_policy to 'restore' for tests
862
            my $manager =
863
              $builder->build_object( { class => "Koha::Patrons" } );
864
            t::lib::Mocks::mock_userenv(
865
                { patron => $manager, branchcode => $manager->branchcode } );
866
            my $specific_rule_restore = $builder->build(
867
                {
868
                    source => 'CirculationRule',
869
                    value  => {
870
                        branchcode   => $manager->branchcode,
871
                        categorycode => undef,
872
                        itemtype     => undef,
873
                        rule_name    => 'lostreturn',
874
                        rule_value   => 'restore'
875
                    }
876
                }
877
            );
878
879
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
880
881
            my $item = $builder->build_sample_item(
882
                {
883
                    biblionumber     => $biblio->biblionumber,
884
                    library          => $library->branchcode,
885
                    replacementprice => $replacement_amount,
886
                    itype            => $item_type->itemtype
887
                }
888
            );
889
890
            my $issue =
891
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
892
893
            # Simulate item marked as lost
894
            $item->itemlost(1)->store;
895
            C4::Circulation::LostItem( $item->itemnumber, 1 );
896
897
            my $processing_fee_lines = Koha::Account::Lines->search(
898
                {
899
                    borrowernumber  => $patron->id,
900
                    itemnumber      => $item->itemnumber,
901
                    debit_type_code => 'PROCESSING'
902
                }
903
            );
904
            is( $processing_fee_lines->count,
905
                1, 'Only one processing fee produced' );
906
            my $processing_fee_line = $processing_fee_lines->next;
907
            is( $processing_fee_line->amount + 0,
908
                $processfee_amount,
909
                'The right PROCESSING amount is generated' );
910
            is( $processing_fee_line->amountoutstanding + 0,
911
                $processfee_amount,
912
                'The right PROCESSING amountoutstanding is generated' );
913
914
            my $lost_fee_lines = Koha::Account::Lines->search(
915
                {
916
                    borrowernumber  => $patron->id,
917
                    itemnumber      => $item->itemnumber,
918
                    debit_type_code => 'LOST'
919
                }
920
            );
921
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
922
            my $lost_fee_line = $lost_fee_lines->next;
923
            is( $lost_fee_line->amount + 0,
924
                $replacement_amount, 'The right LOST amount is generated' );
925
            is( $lost_fee_line->amountoutstanding + 0,
926
                $replacement_amount,
927
                'The right LOST amountountstanding is generated' );
928
929
            my $account = $patron->account;
930
            my $debts   = $account->outstanding_debits;
931
932
            # Pay off the debt
933
            my $credit = $account->add_credit(
934
                {
935
                    amount    => $account->balance,
936
                    type      => 'PAYMENT',
937
                    interface => 'test',
938
                }
939
            );
940
            $credit->apply(
941
                { debits => [ $debts->as_list ], offset_type => 'Payment' } );
942
943
            # Fine not forgiven
944
            my $overdue = $account->add_debit(
945
                {
946
                    amount     => 30.00,
947
                    user_id    => $manager->borrowernumber,
948
                    library_id => $library->branchcode,
949
                    interface  => 'test',
950
                    item_id    => $item->itemnumber,
951
                    type       => 'OVERDUE',
952
                }
953
            )->store();
954
            $overdue->status('LOST')->store();
955
            $overdue->discard_changes;
956
            is( $overdue->status, 'LOST',
957
                'Overdue status set to LOST' );
958
959
            # Simulate item marked as found
960
            $item->itemlost(0)->store;
961
            is( $item->{_refunded}, 1, 'Refund triggered' );
962
            is( $item->{_restored}, undef, 'Restore not triggered when overdue was not forgiven' );
963
            $overdue->discard_changes;
964
            is( $overdue->status, 'FOUND',
965
                'Overdue status updated to FOUND' );
966
        };
967
968
        subtest 'restore fine | forgiven overdue' => sub {
969
970
            plan tests => 12;
971
972
            # Set lostreturn_policy to 'restore' for tests
973
            my $manager =
974
              $builder->build_object( { class => "Koha::Patrons" } );
975
            t::lib::Mocks::mock_userenv(
976
                { patron => $manager, branchcode => $manager->branchcode } );
977
            my $specific_rule_restore = $builder->build(
978
                {
979
                    source => 'CirculationRule',
980
                    value  => {
981
                        branchcode   => $manager->branchcode,
982
                        categorycode => undef,
983
                        itemtype     => undef,
984
                        rule_name    => 'lostreturn',
985
                        rule_value   => 'restore'
986
                    }
987
                }
988
            );
989
990
            my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
991
992
            my $item = $builder->build_sample_item(
993
                {
994
                    biblionumber     => $biblio->biblionumber,
995
                    library          => $library->branchcode,
996
                    replacementprice => $replacement_amount,
997
                    itype            => $item_type->itemtype
998
                }
999
            );
1000
1001
            my $issue =
1002
              C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
1003
1004
            # Simulate item marked as lost
1005
            $item->itemlost(1)->store;
1006
            C4::Circulation::LostItem( $item->itemnumber, 1 );
1007
1008
            my $processing_fee_lines = Koha::Account::Lines->search(
1009
                {
1010
                    borrowernumber  => $patron->id,
1011
                    itemnumber      => $item->itemnumber,
1012
                    debit_type_code => 'PROCESSING'
1013
                }
1014
            );
1015
            is( $processing_fee_lines->count,
1016
                1, 'Only one processing fee produced' );
1017
            my $processing_fee_line = $processing_fee_lines->next;
1018
            is( $processing_fee_line->amount + 0,
1019
                $processfee_amount,
1020
                'The right PROCESSING amount is generated' );
1021
            is( $processing_fee_line->amountoutstanding + 0,
1022
                $processfee_amount,
1023
                'The right PROCESSING amountoutstanding is generated' );
1024
1025
            my $lost_fee_lines = Koha::Account::Lines->search(
1026
                {
1027
                    borrowernumber  => $patron->id,
1028
                    itemnumber      => $item->itemnumber,
1029
                    debit_type_code => 'LOST'
1030
                }
1031
            );
1032
            is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
1033
            my $lost_fee_line = $lost_fee_lines->next;
1034
            is( $lost_fee_line->amount + 0,
1035
                $replacement_amount, 'The right LOST amount is generated' );
1036
            is( $lost_fee_line->amountoutstanding + 0,
1037
                $replacement_amount,
1038
                'The right LOST amountountstanding is generated' );
1039
1040
            my $account = $patron->account;
1041
            my $debts   = $account->outstanding_debits;
1042
1043
            # Pay off the debt
1044
            my $credit = $account->add_credit(
1045
                {
1046
                    amount    => $account->balance,
1047
                    type      => 'PAYMENT',
1048
                    interface => 'test',
1049
                }
1050
            );
1051
            $credit->apply(
1052
                { debits => [ $debts->as_list ], offset_type => 'Payment' } );
1053
1054
            # Add overdue
1055
            my $overdue = $account->add_debit(
1056
                {
1057
                    amount     => 30.00,
1058
                    user_id    => $manager->borrowernumber,
1059
                    library_id => $library->branchcode,
1060
                    interface  => 'test',
1061
                    item_id    => $item->itemnumber,
1062
                    type       => 'OVERDUE',
1063
                }
1064
            )->store();
1065
            $overdue->status('LOST')->store();
1066
            is( $overdue->status, 'LOST',
1067
                'Overdue status set to LOST' );
1068
1069
            # Forgive fine
1070
            $credit = $account->add_credit(
1071
                {
1072
                    amount     => 30.00,
1073
                    user_id    => $manager->borrowernumber,
1074
                    library_id => $library->branchcode,
1075
                    interface  => 'test',
1076
                    type       => 'FORGIVEN',
1077
                    item_id    => $item->itemnumber
1078
                }
1079
            );
1080
            $credit->apply(
1081
                { debits => [$overdue], offset_type => 'Forgiven' } );
1082
1083
            # Simulate item marked as found
1084
            $item->itemlost(0)->store;
1085
            is( $item->{_refunded}, 1, 'Refund triggered' );
1086
            is( $item->{_restored}, 1, 'Restore triggered when overdue was forgiven' );
1087
            $overdue->discard_changes;
1088
            is( $overdue->status, 'FOUND', 'Overdue status updated to FOUND' );
1089
            is( $overdue->amountoutstanding, $overdue->amount, 'Overdue outstanding has been restored' );
1090
            $credit->discard_changes;
1091
            is( $credit->status, 'VOID', 'Overdue Forgival has been marked as VOID');
1092
        };
1093
764
        subtest 'Continue when userenv is not set' => sub {
1094
        subtest 'Continue when userenv is not set' => sub {
765
            plan tests => 1;
1095
            plan tests => 1;
766
1096
767
- 

Return to bug 23091