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

(-)a/C4/Circulation.pm (-136 / +42 lines)
Lines 1519-1569 sub AddIssue { Link Here
1519
            $item_object->store({log_action => 0});
1519
            $item_object->store({log_action => 0});
1520
            ModDateLastSeen( $item_object->itemnumber );
1520
            ModDateLastSeen( $item_object->itemnumber );
1521
1521
1522
            # If the item was lost, it has now been found, restore/charge the overdue if necessary
1522
            # If the item was lost, it has now been found, charge the overdue if necessary
1523
            if ($was_lost) {
1523
            if ($was_lost) {
1524
                my $lostreturn_policy =
1524
                if ( $item_object->{_charge} ) {
1525
                  Koha::CirculationRules->get_lostreturn_policy(
1525
                    $actualissue //= Koha::Old::Checkouts->search(
1526
                    {
1526
                        { itemnumber => $item_unblessed->{itemnumber} },
1527
                        return_branch => C4::Context->userenv->{branch},
1527
                        {
1528
                        item          => $item_object
1528
                            order_by => { '-desc' => 'returndate' },
1529
                    }
1529
                            rows     => 1
1530
                  );
1531
1532
                if ($lostreturn_policy) {
1533
1534
                    if ( $lostreturn_policy eq 'charge' ) {
1535
                        $actualissue //= Koha::Old::Checkouts->search(
1536
                            { itemnumber => $item_unblessed->{itemnumber} },
1537
                            {
1538
                                order_by => { '-desc' => 'returndate' },
1539
                                rows     => 1
1540
                            }
1541
                        )->single;
1542
                        unless ( exists( $borrower->{branchcode} ) ) {
1543
                            my $patron = $actualissue->patron;
1544
                            $borrower = $patron->unblessed;
1545
                        }
1530
                        }
1546
                        _CalculateAndUpdateFine(
1531
                    )->single;
1547
                            {
1532
                    unless ( exists( $borrower->{branchcode} ) ) {
1548
                                issue       => $actualissue,
1533
                        my $patron = $actualissue->patron;
1549
                                item        => $item_unblessed,
1534
                        $borrower = $patron->unblessed;
1550
                                borrower    => $borrower,
1551
                                return_date => $issuedate
1552
                            }
1553
                        );
1554
                        _FixOverduesOnReturn( $borrower->{borrowernumber},
1555
                            $item_object->itemnumber, undef, 'RENEWED' );
1556
                    }
1557
                    elsif ( $lostreturn_policy eq 'restore' ) {
1558
                        _RestoreOverdueForLostAndFound(
1559
                            $item_object->itemnumber );
1560
                    }
1561
1562
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
1563
                        $account->reconcile_balance;
1564
                    }
1535
                    }
1536
                    _CalculateAndUpdateFine(
1537
                        {
1538
                            issue       => $actualissue,
1539
                            item        => $item_unblessed,
1540
                            borrower    => $borrower,
1541
                            return_date => $issuedate
1542
                        }
1543
                    );
1544
                    _FixOverduesOnReturn( $borrower->{borrowernumber},
1545
                        $item_object->itemnumber, undef, 'RENEWED' );
1565
                }
1546
                }
1566
1567
            }
1547
            }
1568
1548
1569
            # If it costs to borrow this book, charge it to the patron's account.
1549
            # If it costs to borrow this book, charge it to the patron's account.
Lines 2067-2112 sub AddReturn { Link Here
2067
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2047
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2068
2048
2069
    # fix up the accounts.....
2049
    # fix up the accounts.....
2070
    if ( $item_was_lost ) {
2050
    if ($item_was_lost) {
2071
        $messages->{'WasLost'} = 1;
2051
        $messages->{'WasLost'} = 1;
2072
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2052
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2073
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2053
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2074
2054
            $messages->{'LostItemFeeRestored'} = $updated_item->{_restored};
2075
            my $lostreturn_policy =
2055
2076
              Koha::CirculationRules->get_lostreturn_policy(
2056
            if ( $updated_item->{_charge} ) {
2077
                {
2057
                $issue //= Koha::Old::Checkouts->search(
2078
                    return_branch => C4::Context->userenv->{branch},
2058
                    { itemnumber => $item->itemnumber },
2079
                    item          => $updated_item
2059
                    { order_by   => { '-desc' => 'returndate' }, rows => 1 } )
2060
                  ->single;
2061
                unless ( exists( $patron_unblessed->{branchcode} ) ) {
2062
                    my $patron = $issue->patron;
2063
                    $patron_unblessed = $patron->unblessed;
2080
                }
2064
                }
2081
              );
2065
                _CalculateAndUpdateFine(
2082
2066
                    {
2083
            if ($lostreturn_policy) {
2067
                        issue       => $issue,
2084
2068
                        item        => $item->unblessed,
2085
                if ( $lostreturn_policy eq 'charge' ) {
2069
                        borrower    => $patron_unblessed,
2086
                    $issue //= Koha::Old::Checkouts->search(
2070
                        return_date => $return_date
2087
                        { itemnumber => $item->itemnumber },
2088
                        { order_by   => { '-desc' => 'returndate' }, rows => 1 }
2089
                    )->single;
2090
                    unless (exists($patron_unblessed->{branchcode})) {
2091
                        my $patron = $issue->patron;
2092
                        $patron_unblessed = $patron->unblessed;
2093
                    }
2071
                    }
2094
                    _CalculateAndUpdateFine(
2072
                );
2095
                        {
2073
                _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2096
                            issue       => $issue,
2074
                    $item->itemnumber, undef, 'RETURNED' );
2097
                            item        => $item->unblessed,
2075
                $messages->{'LostItemFeeCharged'} = 1;
2098
                            borrower    => $patron_unblessed,
2099
                            return_date => $return_date
2100
                        }
2101
                    );
2102
                    _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2103
                        $item->itemnumber, undef, 'RETURNED' );
2104
                    $messages->{'LostItemFeeCharged'} = 1;
2105
                }
2106
                elsif ( $lostreturn_policy eq 'restore' ) {
2107
                    _RestoreOverdueForLostAndFound( $item->itemnumber );
2108
                    $messages->{'LostItemFeeRestored'} = 1;
2109
                }
2110
            }
2076
            }
2111
        }
2077
        }
2112
    }
2078
    }
Lines 2560-2625 sub _FixOverduesOnReturn { Link Here
2560
    return $result;
2526
    return $result;
2561
}
2527
}
2562
2528
2563
=head2 _RestoreOverdueForLostAndFound
2564
2565
   &_RestoreOverdueForLostAndFound( $itemnumber );
2566
2567
C<$itemnumber> itemnumber
2568
2569
Internal function
2570
2571
=cut
2572
2573
sub _RestoreOverdueForLostAndFound {
2574
    my ( $item ) = @_;
2575
2576
    unless( $item ) {
2577
        warn "_RestoreOverdueForLostAndFound() not supplied valid itemnumber";
2578
        return;
2579
    }
2580
2581
    my $schema = Koha::Database->schema;
2582
2583
    my $result = $schema->txn_do(
2584
        sub {
2585
            # check for lost overdue fine
2586
            my $accountlines = Koha::Account::Lines->search(
2587
                {
2588
                    itemnumber      => $item,
2589
                    debit_type_code => 'OVERDUE',
2590
                    status          => 'LOST'
2591
                },
2592
                {
2593
                    order_by => { '-desc' => 'date' },
2594
                    rows     => 1
2595
                }
2596
            );
2597
            return 0 unless $accountlines->count; # no warning, there's just nothing to fix
2598
2599
            # Update status of fine
2600
            my $overdue = $accountlines->next;
2601
            $overdue->status('RETURNED')->store();
2602
2603
            # Find related forgive credit
2604
            my $refunds = $overdue->credits(
2605
                {
2606
                    credit_type_code => 'FORGIVEN',
2607
                    itemnumber       => $item,
2608
                    status           => [ { '!=' => 'VOID' }, undef ]
2609
                },
2610
                { order_by => { '-desc' => 'date' }, rows => 1 }
2611
            );
2612
            return 0 unless $refunds->count; # no warning, there's just nothing to fix
2613
2614
            # Revert the forgive credit
2615
            my $refund = $refunds->next;
2616
            return $refund->void();
2617
        }
2618
    );
2619
2620
    return $result;
2621
}
2622
2623
=head2 _GetCircControlBranch
2529
=head2 _GetCircControlBranch
2624
2530
2625
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
2531
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
(-)a/Koha/Item.pm (-71 / +120 lines)
Lines 807-814 sub _set_found_trigger { Link Here
807
        return $self unless $lost_age_in_days < $no_refund_after_days;
807
        return $self unless $lost_age_in_days < $no_refund_after_days;
808
    }
808
    }
809
809
810
    return $self
810
    my $lostreturn_policy = Koha::CirculationRules->get_lostreturn_policy(
811
      unless Koha::CirculationRules->get_lostreturn_policy(
812
        {
811
        {
813
            item          => $self,
812
            item          => $self,
814
            return_branch => C4::Context->userenv
813
            return_branch => C4::Context->userenv
Lines 817-896 sub _set_found_trigger { Link Here
817
        }
816
        }
818
      );
817
      );
819
818
820
    # check for charge made for lost book
819
    if ( $lostreturn_policy ) {
821
    my $accountlines = Koha::Account::Lines->search(
822
        {
823
            itemnumber      => $self->itemnumber,
824
            debit_type_code => 'LOST',
825
            status          => [ undef, { '<>' => 'FOUND' } ]
826
        },
827
        {
828
            order_by => { -desc => [ 'date', 'accountlines_id' ] }
829
        }
830
    );
831
832
    return $self unless $accountlines->count > 0;
833
834
    my $accountline     = $accountlines->next;
835
    my $total_to_refund = 0;
836
820
837
    return $self unless $accountline->borrowernumber;
821
        # refund charge made for lost book
838
822
        my $lost_charge = Koha::Account::Lines->search(
839
    my $patron = Koha::Patrons->find( $accountline->borrowernumber );
840
    return $self
841
      unless $patron;  # Patron has been deleted, nobody to credit the return to
842
                       # FIXME Should not we notify this somewhere
843
844
    my $account = $patron->account;
845
846
    # Use cases
847
    if ( $accountline->amount > $accountline->amountoutstanding ) {
848
849
    # some amount has been cancelled. collect the offsets that are not writeoffs
850
    # this works because the only way to subtract from this kind of a debt is
851
    # using the UI buttons 'Pay' and 'Write off'
852
        my $credits_offsets = Koha::Account::Offsets->search(
853
            {
823
            {
854
                debit_id  => $accountline->id,
824
                itemnumber      => $self->itemnumber,
855
                credit_id => { '!=' => undef },     # it is not the debit itself
825
                debit_type_code => 'LOST',
856
                type      => { '!=' => 'Writeoff' },
826
                status          => [ undef, { '<>' => 'FOUND' } ]
857
                amount => { '<' => 0 }    # credits are negative on the DB
827
            },
858
            }
859
        );
860
861
        $total_to_refund = ( $credits_offsets->count > 0 )
862
          ? $credits_offsets->total * -1    # credits are negative on the DB
863
          : 0;
864
    }
865
866
    my $credit_total = $accountline->amountoutstanding + $total_to_refund;
867
868
    my $credit;
869
    if ( $credit_total > 0 ) {
870
        my $branchcode =
871
          C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
872
        $credit = $account->add_credit(
873
            {
828
            {
874
                amount      => $credit_total,
829
                order_by => { -desc => [ 'date', 'accountlines_id' ] },
875
                description => 'Item found ' . $self->itemnumber,
830
                rows     => 1
876
                type        => 'LOST_FOUND',
877
                interface   => C4::Context->interface,
878
                library_id  => $branchcode,
879
                item_id     => $self->itemnumber,
880
                issue_id    => $accountline->issue_id
881
            }
831
            }
882
        );
832
        )->single;
883
833
884
        $credit->apply( { debits => [$accountline] } );
834
        if ( $lost_charge ) {
885
        $self->{_refunded} = 1;
835
886
    }
836
            my $patron = $lost_charge->patron;
887
837
            if ( $patron ) {
888
    # Update the account status
838
889
    $accountline->status('FOUND');
839
                my $account = $patron->account;
890
    $accountline->store();
840
                my $total_to_refund = 0;
841
842
                # Use cases
843
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
844
845
                    # some amount has been cancelled. collect the offsets that are not writeoffs
846
                    # this works because the only way to subtract from this kind of a debt is
847
                    # using the UI buttons 'Pay' and 'Write off'
848
                    my $credits_offsets = Koha::Account::Offsets->search(
849
                        {
850
                            debit_id  => $lost_charge->id,
851
                            credit_id => { '!=' => undef },     # it is not the debit itself
852
                            type      => { '!=' => 'Writeoff' },
853
                            amount    => { '<' => 0 }    # credits are negative on the DB
854
                        }
855
                    );
856
857
                    $total_to_refund = ( $credits_offsets->count > 0 )
858
                      ? $credits_offsets->total * -1    # credits are negative on the DB
859
                      : 0;
860
                }
861
862
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
863
864
                my $credit;
865
                if ( $credit_total > 0 ) {
866
                    my $branchcode =
867
                      C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
868
                    $credit = $account->add_credit(
869
                        {
870
                            amount      => $credit_total,
871
                            description => 'Item found ' . $self->itemnumber,
872
                            type        => 'LOST_FOUND',
873
                            interface   => C4::Context->interface,
874
                            library_id  => $branchcode,
875
                            item_id     => $self->itemnumber,
876
                            issue_id    => $lost_charge->issue_id
877
                        }
878
                    );
879
880
                    $credit->apply( { debits => [$lost_charge] } );
881
                    $self->{_refunded} = 1;
882
                }
883
884
                # Update the account status
885
                $lost_charge->status('FOUND');
886
                $lost_charge->store();
887
888
                # Reconcile balances if required
889
                if ( C4::Context->preference('AccountAutoReconcile') ) {
890
                    $account->reconcile_balance;
891
                }
892
            }
893
        }
891
894
892
    if ( defined $account and C4::Context->preference('AccountAutoReconcile') ) {
895
        # restore fine for lost book
893
        $account->reconcile_balance;
896
        if ( $lostreturn_policy eq 'restore' ) {
897
            my $lost_overdue = Koha::Account::Lines->search(
898
                {
899
                    itemnumber      => $self->itemnumber,
900
                    debit_type_code => 'OVERDUE',
901
                    status          => 'LOST'
902
                },
903
                {
904
                    order_by => { '-desc' => 'date' },
905
                    rows     => 1
906
                }
907
            )->single;
908
909
            if ( $lost_overdue ) {
910
911
                my $patron = $lost_overdue->patron;
912
                if ($patron) {
913
                    my $account = $patron->account;
914
915
                    # Update status of fine
916
                    $lost_overdue->status('FOUND')->store();
917
918
                    # Find related forgive credit
919
                    my $refund = $lost_overdue->credits(
920
                        {
921
                            credit_type_code => 'FORGIVEN',
922
                            itemnumber       => $self->itemnumber,
923
                            status           => [ { '!=' => 'VOID' }, undef ]
924
                        },
925
                        { order_by => { '-desc' => 'date' }, rows => 1 }
926
                    )->single;
927
928
                    if ( $refund ) {
929
                        # Revert the forgive credit
930
                        $refund->void();
931
                        $self->{_restored} = 1;
932
                    }
933
934
                    # Reconcile balances if required
935
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
936
                        $account->reconcile_balance;
937
                    }
938
                }
939
            }
940
        } elsif ( $lostreturn_policy eq 'charge' ) {
941
            $self->{_charge} = 1;
942
        }
894
    }
943
    }
895
944
896
    return $self;
945
    return $self;
(-)a/t/db_dependent/Circulation.t (-66 / +1 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 => 48;
22
use Test::Exception;
22
use Test::Exception;
23
use Test::MockModule;
23
use Test::MockModule;
24
use Test::Deep qw( cmp_deeply );
24
use Test::Deep qw( cmp_deeply );
Lines 2752-2822 subtest 'AddReturn | is_overdue' => sub { Link Here
2752
    };
2752
    };
2753
};
2753
};
2754
2754
2755
subtest '_RestoreOverdueForLostAndFound' => sub {
2756
2757
    plan tests => 7;
2758
2759
    my $manager = $builder->build_object( { class => "Koha::Patrons" } );
2760
    t::lib::Mocks::mock_userenv(
2761
        { patron => $manager, branchcode => $manager->branchcode } );
2762
2763
    my $patron = $builder->build_object( { class => "Koha::Patrons" } );
2764
    my $item = $builder->build_sample_item();
2765
2766
    # No fine found
2767
    my $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2768
    is($result, 0, "0 returned when no overdue found");
2769
2770
    # Fine not forgiven
2771
    my $account = $patron->account;
2772
    my $overdue = $account->add_debit(
2773
        {
2774
            amount     => 30.00,
2775
            user_id    => $manager->borrowernumber,
2776
            library_id => $library2->{branchcode},
2777
            interface  => 'test',
2778
            item_id    => $item->itemnumber,
2779
            type       => 'OVERDUE',
2780
        }
2781
    )->store();
2782
    $overdue->status('LOST')->store();
2783
2784
    $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2785
    is($result, 0, "0 returned when overdue found without forgival");
2786
    $overdue->discard_changes;
2787
    is($overdue->status, 'RETURNED', 'Overdue status updated to RETURNED');
2788
2789
    # Reset status
2790
    $overdue->status('LOST')->store();
2791
2792
    # Fine forgiven
2793
    my $credit = $account->add_credit(
2794
        {
2795
            amount     => 30.00,
2796
            user_id    => $manager->borrowernumber,
2797
            library_id => $library2->{branchcode},
2798
            interface  => 'test',
2799
            type       => 'FORGIVEN',
2800
            item_id    => $item->itemnumber
2801
        }
2802
    );
2803
    $credit->apply( { debits => [$overdue], offset_type => 'Forgiven' } );
2804
2805
    $result = C4::Circulation::_RestoreOverdueForLostAndFound( $item->itemnumber);
2806
2807
    is( ref($result), 'Koha::Account::Line', 'Return a Koha::Account::Line object on sucess');
2808
    $overdue->discard_changes;
2809
    is($overdue->status, 'RETURNED', 'Overdue status updated to RETURNED');
2810
    is($overdue->amountoutstanding, $overdue->amount, 'Overdue outstanding restored');
2811
2812
    # Missing parameters
2813
    warning_like {
2814
        C4::Circulation::_RestoreOverdueForLostAndFound( undef )
2815
    }
2816
    qr/_RestoreOverdueForLostAndFound\(\) not supplied valid itemnumber/,
2817
      "parameter warning received for missing itemnumbernumber";
2818
};
2819
2820
subtest '_FixOverduesOnReturn' => sub {
2755
subtest '_FixOverduesOnReturn' => sub {
2821
    plan tests => 14;
2756
    plan tests => 14;
2822
2757
(-)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