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

(-)a/C4/Circulation.pm (-136 / +42 lines)
Lines 1530-1580 sub AddIssue { Link Here
1530
            $item_object->store({log_action => 0});
1530
            $item_object->store({log_action => 0});
1531
            ModDateLastSeen( $item_object->itemnumber );
1531
            ModDateLastSeen( $item_object->itemnumber );
1532
1532
1533
            # If the item was lost, it has now been found, restore/charge the overdue if necessary
1533
            # If the item was lost, it has now been found, charge the overdue if necessary
1534
            if ($was_lost) {
1534
            if ($was_lost) {
1535
                my $lostreturn_policy =
1535
                if ( $item_object->{_charge} ) {
1536
                  Koha::CirculationRules->get_lostreturn_policy(
1536
                    $actualissue //= Koha::Old::Checkouts->search(
1537
                    {
1537
                        { itemnumber => $item_unblessed->{itemnumber} },
1538
                        return_branch => C4::Context->userenv->{branch},
1538
                        {
1539
                        item          => $item_object
1539
                            order_by => { '-desc' => 'returndate' },
1540
                    }
1540
                            rows     => 1
1541
                  );
1542
1543
                if ($lostreturn_policy) {
1544
1545
                    if ( $lostreturn_policy eq 'charge' ) {
1546
                        $actualissue //= Koha::Old::Checkouts->search(
1547
                            { itemnumber => $item_unblessed->{itemnumber} },
1548
                            {
1549
                                order_by => { '-desc' => 'returndate' },
1550
                                rows     => 1
1551
                            }
1552
                        )->single;
1553
                        unless ( exists( $borrower->{branchcode} ) ) {
1554
                            my $patron = $actualissue->patron;
1555
                            $borrower = $patron->unblessed;
1556
                        }
1541
                        }
1557
                        _CalculateAndUpdateFine(
1542
                    )->single;
1558
                            {
1543
                    unless ( exists( $borrower->{branchcode} ) ) {
1559
                                issue       => $actualissue,
1544
                        my $patron = $actualissue->patron;
1560
                                item        => $item_unblessed,
1545
                        $borrower = $patron->unblessed;
1561
                                borrower    => $borrower,
1562
                                return_date => $issuedate
1563
                            }
1564
                        );
1565
                        _FixOverduesOnReturn( $borrower->{borrowernumber},
1566
                            $item_object->itemnumber, undef, 'RENEWED' );
1567
                    }
1568
                    elsif ( $lostreturn_policy eq 'restore' ) {
1569
                        _RestoreOverdueForLostAndFound(
1570
                            $item_object->itemnumber );
1571
                    }
1572
1573
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
1574
                        $account->reconcile_balance;
1575
                    }
1546
                    }
1547
                    _CalculateAndUpdateFine(
1548
                        {
1549
                            issue       => $actualissue,
1550
                            item        => $item_unblessed,
1551
                            borrower    => $borrower,
1552
                            return_date => $issuedate
1553
                        }
1554
                    );
1555
                    _FixOverduesOnReturn( $borrower->{borrowernumber},
1556
                        $item_object->itemnumber, undef, 'RENEWED' );
1576
                }
1557
                }
1577
1578
            }
1558
            }
1579
1559
1580
            # If it costs to borrow this book, charge it to the patron's account.
1560
            # If it costs to borrow this book, charge it to the patron's account.
Lines 2078-2123 sub AddReturn { Link Here
2078
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2058
    my $updated_item = ModDateLastSeen( $item->itemnumber, $leave_item_lost ); # will unset itemlost if needed
2079
2059
2080
    # fix up the accounts.....
2060
    # fix up the accounts.....
2081
    if ( $item_was_lost ) {
2061
    if ($item_was_lost) {
2082
        $messages->{'WasLost'} = 1;
2062
        $messages->{'WasLost'} = 1;
2083
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2063
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2084
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2064
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2085
2065
            $messages->{'LostItemFeeRestored'} = $updated_item->{_restored};
2086
            my $lostreturn_policy =
2066
2087
              Koha::CirculationRules->get_lostreturn_policy(
2067
            if ( $updated_item->{_charge} ) {
2088
                {
2068
                $issue //= Koha::Old::Checkouts->search(
2089
                    return_branch => C4::Context->userenv->{branch},
2069
                    { itemnumber => $item->itemnumber },
2090
                    item          => $updated_item
2070
                    { order_by   => { '-desc' => 'returndate' }, rows => 1 } )
2071
                  ->single;
2072
                unless ( exists( $patron_unblessed->{branchcode} ) ) {
2073
                    my $patron = $issue->patron;
2074
                    $patron_unblessed = $patron->unblessed;
2091
                }
2075
                }
2092
              );
2076
                _CalculateAndUpdateFine(
2093
2077
                    {
2094
            if ($lostreturn_policy) {
2078
                        issue       => $issue,
2095
2079
                        item        => $item->unblessed,
2096
                if ( $lostreturn_policy eq 'charge' ) {
2080
                        borrower    => $patron_unblessed,
2097
                    $issue //= Koha::Old::Checkouts->search(
2081
                        return_date => $return_date
2098
                        { itemnumber => $item->itemnumber },
2099
                        { order_by   => { '-desc' => 'returndate' }, rows => 1 }
2100
                    )->single;
2101
                    unless (exists($patron_unblessed->{branchcode})) {
2102
                        my $patron = $issue->patron;
2103
                        $patron_unblessed = $patron->unblessed;
2104
                    }
2082
                    }
2105
                    _CalculateAndUpdateFine(
2083
                );
2106
                        {
2084
                _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2107
                            issue       => $issue,
2085
                    $item->itemnumber, undef, 'RETURNED' );
2108
                            item        => $item->unblessed,
2086
                $messages->{'LostItemFeeCharged'} = 1;
2109
                            borrower    => $patron_unblessed,
2110
                            return_date => $return_date
2111
                        }
2112
                    );
2113
                    _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2114
                        $item->itemnumber, undef, 'RETURNED' );
2115
                    $messages->{'LostItemFeeCharged'} = 1;
2116
                }
2117
                elsif ( $lostreturn_policy eq 'restore' ) {
2118
                    _RestoreOverdueForLostAndFound( $item->itemnumber );
2119
                    $messages->{'LostItemFeeRestored'} = 1;
2120
                }
2121
            }
2087
            }
2122
        }
2088
        }
2123
    }
2089
    }
Lines 2571-2636 sub _FixOverduesOnReturn { Link Here
2571
    return $result;
2537
    return $result;
2572
}
2538
}
2573
2539
2574
=head2 _RestoreOverdueForLostAndFound
2575
2576
   &_RestoreOverdueForLostAndFound( $itemnumber );
2577
2578
C<$itemnumber> itemnumber
2579
2580
Internal function
2581
2582
=cut
2583
2584
sub _RestoreOverdueForLostAndFound {
2585
    my ( $item ) = @_;
2586
2587
    unless( $item ) {
2588
        warn "_RestoreOverdueForLostAndFound() not supplied valid itemnumber";
2589
        return;
2590
    }
2591
2592
    my $schema = Koha::Database->schema;
2593
2594
    my $result = $schema->txn_do(
2595
        sub {
2596
            # check for lost overdue fine
2597
            my $accountlines = Koha::Account::Lines->search(
2598
                {
2599
                    itemnumber      => $item,
2600
                    debit_type_code => 'OVERDUE',
2601
                    status          => 'LOST'
2602
                },
2603
                {
2604
                    order_by => { '-desc' => 'date' },
2605
                    rows     => 1
2606
                }
2607
            );
2608
            return 0 unless $accountlines->count; # no warning, there's just nothing to fix
2609
2610
            # Update status of fine
2611
            my $overdue = $accountlines->next;
2612
            $overdue->status('RETURNED')->store();
2613
2614
            # Find related forgive credit
2615
            my $refunds = $overdue->credits(
2616
                {
2617
                    credit_type_code => 'FORGIVEN',
2618
                    itemnumber       => $item,
2619
                    status           => [ { '!=' => 'VOID' }, undef ]
2620
                },
2621
                { order_by => { '-desc' => 'date' }, rows => 1 }
2622
            );
2623
            return 0 unless $refunds->count; # no warning, there's just nothing to fix
2624
2625
            # Revert the forgive credit
2626
            my $refund = $refunds->next;
2627
            return $refund->void();
2628
        }
2629
    );
2630
2631
    return $result;
2632
}
2633
2634
=head2 _GetCircControlBranch
2540
=head2 _GetCircControlBranch
2635
2541
2636
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
2542
   my $circ_control_branch = _GetCircControlBranch($iteminfos, $borrower);
(-)a/Koha/Item.pm (-71 / +120 lines)
Lines 808-815 sub _set_found_trigger { Link Here
808
        return $self unless $lost_age_in_days < $no_refund_after_days;
808
        return $self unless $lost_age_in_days < $no_refund_after_days;
809
    }
809
    }
810
810
811
    return $self
811
    my $lostreturn_policy = Koha::CirculationRules->get_lostreturn_policy(
812
      unless Koha::CirculationRules->get_lostreturn_policy(
813
        {
812
        {
814
            item          => $self,
813
            item          => $self,
815
            return_branch => C4::Context->userenv
814
            return_branch => C4::Context->userenv
Lines 818-897 sub _set_found_trigger { Link Here
818
        }
817
        }
819
      );
818
      );
820
819
821
    # check for charge made for lost book
820
    if ( $lostreturn_policy ) {
822
    my $accountlines = Koha::Account::Lines->search(
823
        {
824
            itemnumber      => $self->itemnumber,
825
            debit_type_code => 'LOST',
826
            status          => [ undef, { '<>' => 'FOUND' } ]
827
        },
828
        {
829
            order_by => { -desc => [ 'date', 'accountlines_id' ] }
830
        }
831
    );
832
833
    return $self unless $accountlines->count > 0;
834
835
    my $accountline     = $accountlines->next;
836
    my $total_to_refund = 0;
837
821
838
    return $self unless $accountline->borrowernumber;
822
        # refund charge made for lost book
839
823
        my $lost_charge = Koha::Account::Lines->search(
840
    my $patron = Koha::Patrons->find( $accountline->borrowernumber );
841
    return $self
842
      unless $patron;  # Patron has been deleted, nobody to credit the return to
843
                       # FIXME Should not we notify this somewhere
844
845
    my $account = $patron->account;
846
847
    # Use cases
848
    if ( $accountline->amount > $accountline->amountoutstanding ) {
849
850
    # some amount has been cancelled. collect the offsets that are not writeoffs
851
    # this works because the only way to subtract from this kind of a debt is
852
    # using the UI buttons 'Pay' and 'Write off'
853
        my $credits_offsets = Koha::Account::Offsets->search(
854
            {
824
            {
855
                debit_id  => $accountline->id,
825
                itemnumber      => $self->itemnumber,
856
                credit_id => { '!=' => undef },     # it is not the debit itself
826
                debit_type_code => 'LOST',
857
                type      => { '!=' => 'Writeoff' },
827
                status          => [ undef, { '<>' => 'FOUND' } ]
858
                amount => { '<' => 0 }    # credits are negative on the DB
828
            },
859
            }
860
        );
861
862
        $total_to_refund = ( $credits_offsets->count > 0 )
863
          ? $credits_offsets->total * -1    # credits are negative on the DB
864
          : 0;
865
    }
866
867
    my $credit_total = $accountline->amountoutstanding + $total_to_refund;
868
869
    my $credit;
870
    if ( $credit_total > 0 ) {
871
        my $branchcode =
872
          C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
873
        $credit = $account->add_credit(
874
            {
829
            {
875
                amount      => $credit_total,
830
                order_by => { -desc => [ 'date', 'accountlines_id' ] },
876
                description => 'Item found ' . $self->itemnumber,
831
                rows     => 1
877
                type        => 'LOST_FOUND',
878
                interface   => C4::Context->interface,
879
                library_id  => $branchcode,
880
                item_id     => $self->itemnumber,
881
                issue_id    => $accountline->issue_id
882
            }
832
            }
883
        );
833
        )->single;
884
834
885
        $credit->apply( { debits => [$accountline] } );
835
        if ( $lost_charge ) {
886
        $self->{_refunded} = 1;
836
887
    }
837
            my $patron = $lost_charge->patron;
888
838
            if ( $patron ) {
889
    # Update the account status
839
890
    $accountline->status('FOUND');
840
                my $account = $patron->account;
891
    $accountline->store();
841
                my $total_to_refund = 0;
842
843
                # Use cases
844
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
845
846
                    # some amount has been cancelled. collect the offsets that are not writeoffs
847
                    # this works because the only way to subtract from this kind of a debt is
848
                    # using the UI buttons 'Pay' and 'Write off'
849
                    my $credits_offsets = Koha::Account::Offsets->search(
850
                        {
851
                            debit_id  => $lost_charge->id,
852
                            credit_id => { '!=' => undef },     # it is not the debit itself
853
                            type      => { '!=' => 'Writeoff' },
854
                            amount    => { '<' => 0 }    # credits are negative on the DB
855
                        }
856
                    );
857
858
                    $total_to_refund = ( $credits_offsets->count > 0 )
859
                      ? $credits_offsets->total * -1    # credits are negative on the DB
860
                      : 0;
861
                }
862
863
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
864
865
                my $credit;
866
                if ( $credit_total > 0 ) {
867
                    my $branchcode =
868
                      C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
869
                    $credit = $account->add_credit(
870
                        {
871
                            amount      => $credit_total,
872
                            description => 'Item found ' . $self->itemnumber,
873
                            type        => 'LOST_FOUND',
874
                            interface   => C4::Context->interface,
875
                            library_id  => $branchcode,
876
                            item_id     => $self->itemnumber,
877
                            issue_id    => $lost_charge->issue_id
878
                        }
879
                    );
880
881
                    $credit->apply( { debits => [$lost_charge] } );
882
                    $self->{_refunded} = 1;
883
                }
884
885
                # Update the account status
886
                $lost_charge->status('FOUND');
887
                $lost_charge->store();
888
889
                # Reconcile balances if required
890
                if ( C4::Context->preference('AccountAutoReconcile') ) {
891
                    $account->reconcile_balance;
892
                }
893
            }
894
        }
892
895
893
    if ( defined $account and C4::Context->preference('AccountAutoReconcile') ) {
896
        # restore fine for lost book
894
        $account->reconcile_balance;
897
        if ( $lostreturn_policy eq 'restore' ) {
898
            my $lost_overdue = Koha::Account::Lines->search(
899
                {
900
                    itemnumber      => $self->itemnumber,
901
                    debit_type_code => 'OVERDUE',
902
                    status          => 'LOST'
903
                },
904
                {
905
                    order_by => { '-desc' => 'date' },
906
                    rows     => 1
907
                }
908
            )->single;
909
910
            if ( $lost_overdue ) {
911
912
                my $patron = $lost_overdue->patron;
913
                if ($patron) {
914
                    my $account = $patron->account;
915
916
                    # Update status of fine
917
                    $lost_overdue->status('FOUND')->store();
918
919
                    # Find related forgive credit
920
                    my $refund = $lost_overdue->credits(
921
                        {
922
                            credit_type_code => 'FORGIVEN',
923
                            itemnumber       => $self->itemnumber,
924
                            status           => [ { '!=' => 'VOID' }, undef ]
925
                        },
926
                        { order_by => { '-desc' => 'date' }, rows => 1 }
927
                    )->single;
928
929
                    if ( $refund ) {
930
                        # Revert the forgive credit
931
                        $refund->void();
932
                        $self->{_restored} = 1;
933
                    }
934
935
                    # Reconcile balances if required
936
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
937
                        $account->reconcile_balance;
938
                    }
939
                }
940
            }
941
        } elsif ( $lostreturn_policy eq 'charge' ) {
942
            $self->{_charge} = 1;
943
        }
895
    }
944
    }
896
945
897
    return $self;
946
    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