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

(-)a/Koha/Item.pm (-8 / +22 lines)
Lines 997-1010 sub _set_found_trigger { Link Here
997
            if ( $patron ) {
997
            if ( $patron ) {
998
998
999
                my $account = $patron->account;
999
                my $account = $patron->account;
1000
                my $total_to_refund = 0;
1001
1000
1002
                # Use cases
1001
                # Credit outstanding amount
1003
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
1002
                my $credit_total = $lost_charge->amountoutstanding;
1004
1003
1004
                # Use cases
1005
                if (
1006
                    $lost_charge->amount > $lost_charge->amountoutstanding &&
1007
                    $lostreturn_policy ne "refund_unpaid"
1008
                ) {
1005
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1009
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1006
                    # this works because the only way to subtract from this kind of a debt is
1010
                    # this works because the only way to subtract from this kind of a debt is
1007
                    # using the UI buttons 'Pay' and 'Write off'
1011
                    # using the UI buttons 'Pay' and 'Write off'
1012
1013
                    # We don't credit any payments if return policy is
1014
                    # "refund_unpaid"
1015
                    #
1016
                    # In that case only unpaid/outstanding amount
1017
                    # will be credited wich settles the debt without
1018
                    # creating extra credits
1019
1008
                    my $credit_offsets = $lost_charge->debit_offsets(
1020
                    my $credit_offsets = $lost_charge->debit_offsets(
1009
                        {
1021
                        {
1010
                            'credit_id'               => { '!=' => undef },
1022
                            'credit_id'               => { '!=' => undef },
Lines 1013-1025 sub _set_found_trigger { Link Here
1013
                        { join => 'credit' }
1025
                        { join => 'credit' }
1014
                    );
1026
                    );
1015
1027
1016
                    $total_to_refund = ( $credit_offsets->count > 0 )
1028
                    my $total_to_refund = ( $credit_offsets->count > 0 ) ?
1017
                      ? $credit_offsets->total * -1    # credits are negative on the DB
1029
                        # credits are negative on the DB
1018
                      : 0;
1030
                        $credit_offsets->total * -1 :
1031
                        0;
1032
                    # Credit the outstanding amount, then add what has been
1033
                    # paid to create a net credit for this amount
1034
                    $credit_total += $total_to_refund;
1019
                }
1035
                }
1020
1036
1021
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
1022
1023
                my $credit;
1037
                my $credit;
1024
                if ( $credit_total > 0 ) {
1038
                if ( $credit_total > 0 ) {
1025
                    my $branchcode =
1039
                    my $branchcode =
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (+24 lines)
Lines 810-835 Link Here
810
                          [% IF ( current_branch == '*' ) %]
810
                          [% IF ( current_branch == '*' ) %]
811
                            [% IF ( defaultRefundRule == 'refund' ) %]
811
                            [% IF ( defaultRefundRule == 'refund' ) %]
812
                            <option value="refund" selected="selected">Refund lost item charge</option>
812
                            <option value="refund" selected="selected">Refund lost item charge</option>
813
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
814
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
815
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
816
                            <option value="0">Leave lost item charge</option>
817
                            [% ELSIF ( defaultRefundRule == 'refund_unpaid' ) %]
818
                            <option value="refund">Refund lost item charge</option>
819
                            <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
813
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
820
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
814
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
821
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
815
                            <option value="0">Leave lost item charge</option>
822
                            <option value="0">Leave lost item charge</option>
816
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
823
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
817
                            <option value="refund">Refund lost item charge</option>
824
                            <option value="refund">Refund lost item charge</option>
825
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
818
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
826
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
819
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
827
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
820
                            <option value="0">Leave lost item charge</option>
828
                            <option value="0">Leave lost item charge</option>
821
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
829
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
822
                            <option value="refund">Refund lost item charge</option>
830
                            <option value="refund">Refund lost item charge</option>
831
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
823
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
832
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
824
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
833
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
825
                            <option value="0">Leave lost item charge</option>
834
                            <option value="0">Leave lost item charge</option>
826
                            [% ELSIF ( defaultRefundRule == 0 ) %]
835
                            [% ELSIF ( defaultRefundRule == 0 ) %]
827
                            <option value="refund">Refund lost item charge</option>
836
                            <option value="refund">Refund lost item charge</option>
837
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
828
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
838
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
829
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
839
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
830
                            <option value="0" selected="selected">Leave lost item charge</option>
840
                            <option value="0" selected="selected">Leave lost item charge</option>
831
                            [% ELSE %]
841
                            [% ELSE %]
832
                            <option value="refund">Refund lost item charge</option>
842
                            <option value="refund">Refund lost item charge</option>
843
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
833
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
844
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
834
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
845
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
835
                            <option value="0">Leave lost item charge</option>
846
                            <option value="0">Leave lost item charge</option>
Lines 843-848 Link Here
843
                            [% END %]
854
                            [% END %]
844
                              [% IF defaultRefundRule == 'refund' %]
855
                              [% IF defaultRefundRule == 'refund' %]
845
                                Use default (Refund lost item charge)
856
                                Use default (Refund lost item charge)
857
                              [% ELSIF defaultRefundRule == 'refund_unpaid' %]
858
                                Use default (Refund lost item charge (only if unpaid))
846
                              [% ELSIF defaultRefundRule == 'charge' %]
859
                              [% ELSIF defaultRefundRule == 'charge' %]
847
                                Use default (Refund lost item charge and restore overdue fine)
860
                                Use default (Refund lost item charge and restore overdue fine)
848
                              [% ELSIF defaultRefundRule == 'restore' %]
861
                              [% ELSIF defaultRefundRule == 'restore' %]
Lines 853-879 Link Here
853
                                </option>
866
                                </option>
854
                            [% IF ( not refundLostItemFeeRule ) %]
867
                            [% IF ( not refundLostItemFeeRule ) %]
855
                                <option value="refund">Refund lost item charge</option>
868
                                <option value="refund">Refund lost item charge</option>
869
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
856
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
870
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
857
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
871
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
858
                                <option value="0">Leave lost item charge</option>
872
                                <option value="0">Leave lost item charge</option>
859
                            [% ELSE %]
873
                            [% ELSE %]
860
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
874
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
861
                                <option value="refund" selected="selected">Refund lost item charge</option>
875
                                <option value="refund" selected="selected">Refund lost item charge</option>
876
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
862
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
877
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
863
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
878
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
864
                                <option value="0">Leave lost item charge</option>
879
                                <option value="0">Leave lost item charge</option>
880
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'refund_unpaid' ) %]
881
                                <option value="refund">Refund lost item charge</option>
882
                                <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
883
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
884
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
885
                                <option value="0">Leave lost item charge</option>
865
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
886
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
866
                                <option value="refund">Refund lost item charge</option>
887
                                <option value="refund">Refund lost item charge</option>
888
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
867
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
889
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
868
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
890
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
869
                                <option value="0">Leave lost item charge</option>
891
                                <option value="0">Leave lost item charge</option>
870
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
892
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
871
                                <option value="refund">Refund lost item charge</option>
893
                                <option value="refund">Refund lost item charge</option>
894
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
872
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
895
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
873
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
896
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
874
                                <option value="0">Leave lost item charge</option>
897
                                <option value="0">Leave lost item charge</option>
875
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
898
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
876
                                <option value="refund">Refund lost item charge</option>
899
                                <option value="refund">Refund lost item charge</option>
900
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
877
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
901
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
878
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
902
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
879
                                <option value="0" selected="selected">Leave lost item charge</option>
903
                                <option value="0" selected="selected">Leave lost item charge</option>
(-)a/t/db_dependent/Circulation.t (-2 / +191 lines)
Lines 2883-2889 subtest 'AddReturn | is_overdue' => sub { Link Here
2883
    };
2883
    };
2884
2884
2885
    subtest 'enh 23091 | Lost item return policies' => sub {
2885
    subtest 'enh 23091 | Lost item return policies' => sub {
2886
        plan tests => 4;
2886
        plan tests => 5;
2887
2887
2888
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
2888
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
2889
2889
Lines 2944-2949 subtest 'AddReturn | is_overdue' => sub { Link Here
2944
            }
2944
            }
2945
        );
2945
        );
2946
2946
2947
        my $branchcode_refund_unpaid =
2948
        $builder->build( { source => 'Branch' } )->{branchcode};
2949
        my $specific_rule_refund_unpaid = $builder->build(
2950
            {
2951
                source => 'CirculationRule',
2952
                value  => {
2953
                    branchcode   => $branchcode_refund_unpaid,
2954
                    categorycode => undef,
2955
                    itemtype     => undef,
2956
                    rule_name    => 'lostreturn',
2957
                    rule_value   => 'refund_unpaid'
2958
                }
2959
            }
2960
        );
2961
2947
        my $replacement_amount = 99.00;
2962
        my $replacement_amount = 99.00;
2948
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
2963
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
2949
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
2964
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
Lines 2954-2959 subtest 'AddReturn | is_overdue' => sub { Link Here
2954
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
2969
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
2955
            undef );
2970
            undef );
2956
2971
2972
        subtest 'lostreturn | refund_unpaid' => sub {
2973
            plan tests => 21;
2974
2975
            t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_refund_unpaid });
2976
2977
            my $item = $builder->build_sample_item(
2978
                {
2979
                    replacementprice => $replacement_amount
2980
                }
2981
            );
2982
2983
            # Issue the item
2984
            my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
2985
2986
            # Mark item as lost
2987
            $item->itemlost(3)->store;
2988
            C4::Circulation::LostItem( $item->itemnumber, 1 );
2989
2990
            my $lost_fee_lines = Koha::Account::Lines->search(
2991
                {
2992
                    borrowernumber  => $patron->id,
2993
                    itemnumber      => $item->itemnumber,
2994
                    debit_type_code => 'LOST'
2995
                }
2996
            );
2997
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
2998
            my $lost_fee_line = $lost_fee_lines->next;
2999
            is( int($lost_fee_line->amount),
3000
                $replacement_amount, 'The right LOST amount is generated' );
3001
            is( int($lost_fee_line->amountoutstanding),
3002
                $replacement_amount,
3003
                'The right LOST amountoutstanding is generated' );
3004
            is( $lost_fee_line->status, undef, 'The LOST status was not set' );
3005
3006
            is(
3007
                int($patron->account->balance),
3008
                $replacement_amount ,
3009
                "Account balance equals the replacement amount after being charged lost fee when no payments has been made"
3010
            );
3011
3012
            # Return lost item without any payments having been made
3013
            my ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3014
3015
            $lost_fee_line->discard_changes;
3016
3017
            is( int($lost_fee_line->amount), $replacement_amount, 'The LOST amount is left intact' );
3018
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero' );
3019
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set' );
3020
            is(
3021
                int($patron->account->balance),
3022
                0,
3023
                'Account balance should be zero after returning item with lost fee when no payments has been made'
3024
            );
3025
3026
            # Create a second item
3027
            $item = $builder->build_sample_item(
3028
                {
3029
                    replacementprice => $replacement_amount
3030
                }
3031
            );
3032
3033
            # Issue the item
3034
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3035
3036
            # Mark item as lost
3037
            $item->itemlost(3)->store;
3038
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3039
3040
            $lost_fee_lines = Koha::Account::Lines->search(
3041
                {
3042
                    borrowernumber  => $patron->id,
3043
                    itemnumber      => $item->itemnumber,
3044
                    debit_type_code => 'LOST'
3045
                }
3046
            );
3047
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3048
            $lost_fee_line = $lost_fee_lines->next;
3049
3050
            # Make partial payment
3051
            $patron->account->payin_amount({
3052
                type => 'PAYMENT',
3053
                interface => 'intranet',
3054
                payment_type => 'CASH',
3055
                user_id => $patron->borrowernumber,
3056
                amount => 39.00,
3057
                lines => [$lost_fee_line]
3058
            });
3059
3060
            $lost_fee_line->discard_changes;
3061
3062
            is( int($lost_fee_line->amountoutstanding),
3063
                60,
3064
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3065
            );
3066
3067
            is(
3068
                int($patron->account->balance),
3069
                60,
3070
                'Account balance is the expected amount after partial payment of lost fee'
3071
            );
3072
3073
             # Return lost item with partial payment having been made
3074
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3075
3076
            $lost_fee_line->discard_changes;
3077
3078
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with partial payment' );
3079
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item with partial payment' );
3080
            is(
3081
                int($patron->account->balance),
3082
                0,
3083
                'Account balance should be zero after returning item with lost fee when partial payment has been made'
3084
            );
3085
3086
            # Create a third item
3087
            $item = $builder->build_sample_item(
3088
                {
3089
                    replacementprice => $replacement_amount
3090
                }
3091
            );
3092
3093
            # Issue the item
3094
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3095
3096
            # Mark item as lost
3097
            $item->itemlost(3)->store;
3098
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3099
3100
            $lost_fee_lines = Koha::Account::Lines->search(
3101
                {
3102
                    borrowernumber  => $patron->id,
3103
                    itemnumber      => $item->itemnumber,
3104
                    debit_type_code => 'LOST'
3105
                }
3106
            );
3107
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3108
            $lost_fee_line = $lost_fee_lines->next;
3109
3110
            # Make full payment
3111
            $patron->account->payin_amount({
3112
                type => 'PAYMENT',
3113
                interface => 'intranet',
3114
                payment_type => 'CASH',
3115
                user_id => $patron->borrowernumber,
3116
                amount => $replacement_amount,
3117
                lines => [$lost_fee_line]
3118
            });
3119
3120
            $lost_fee_line->discard_changes;
3121
3122
            is( int($lost_fee_line->amountoutstanding),
3123
                0,
3124
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3125
            );
3126
3127
            is(
3128
                int($patron->account->balance),
3129
                0,
3130
                'Account balance is the expected amount after partial payment of lost fee'
3131
            );
3132
3133
             # Return lost item with partial payment having been made
3134
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3135
3136
            $lost_fee_line->discard_changes;
3137
3138
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with full payment' );
3139
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item iwth partial payment' );
3140
            is(
3141
                int($patron->account->balance),
3142
                0,
3143
                'Account balance should be zero after returning item with lost fee when full payment has been made'
3144
            );
3145
        };
3146
2957
        subtest 'lostreturn | false' => sub {
3147
        subtest 'lostreturn | false' => sub {
2958
            plan tests => 12;
3148
            plan tests => 12;
2959
3149
2960
- 

Return to bug 20262