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

(-)a/Koha/Item.pm (-8 / +22 lines)
Lines 1118-1131 sub _set_found_trigger { Link Here
1118
            if ( $patron ) {
1118
            if ( $patron ) {
1119
1119
1120
                my $account = $patron->account;
1120
                my $account = $patron->account;
1121
                my $total_to_refund = 0;
1122
1121
1123
                # Use cases
1122
                # Credit outstanding amount
1124
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
1123
                my $credit_total = $lost_charge->amountoutstanding;
1125
1124
1125
                # Use cases
1126
                if (
1127
                    $lost_charge->amount > $lost_charge->amountoutstanding &&
1128
                    $lostreturn_policy ne "refund_unpaid"
1129
                ) {
1126
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1130
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1127
                    # this works because the only way to subtract from this kind of a debt is
1131
                    # this works because the only way to subtract from this kind of a debt is
1128
                    # using the UI buttons 'Pay' and 'Write off'
1132
                    # using the UI buttons 'Pay' and 'Write off'
1133
1134
                    # We don't credit any payments if return policy is
1135
                    # "refund_unpaid"
1136
                    #
1137
                    # In that case only unpaid/outstanding amount
1138
                    # will be credited wich settles the debt without
1139
                    # creating extra credits
1140
1129
                    my $credit_offsets = $lost_charge->debit_offsets(
1141
                    my $credit_offsets = $lost_charge->debit_offsets(
1130
                        {
1142
                        {
1131
                            'credit_id'               => { '!=' => undef },
1143
                            'credit_id'               => { '!=' => undef },
Lines 1134-1146 sub _set_found_trigger { Link Here
1134
                        { join => 'credit' }
1146
                        { join => 'credit' }
1135
                    );
1147
                    );
1136
1148
1137
                    $total_to_refund = ( $credit_offsets->count > 0 )
1149
                    my $total_to_refund = ( $credit_offsets->count > 0 ) ?
1138
                      ? $credit_offsets->total * -1    # credits are negative on the DB
1150
                        # credits are negative on the DB
1139
                      : 0;
1151
                        $credit_offsets->total * -1 :
1152
                        0;
1153
                    # Credit the outstanding amount, then add what has been
1154
                    # paid to create a net credit for this amount
1155
                    $credit_total += $total_to_refund;
1140
                }
1156
                }
1141
1157
1142
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
1143
1144
                my $credit;
1158
                my $credit;
1145
                if ( $credit_total > 0 ) {
1159
                if ( $credit_total > 0 ) {
1146
                    my $branchcode =
1160
                    my $branchcode =
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (+24 lines)
Lines 974-999 Link Here
974
                          [% IF ( current_branch == '*' ) %]
974
                          [% IF ( current_branch == '*' ) %]
975
                            [% IF ( defaultRefundRule == 'refund' ) %]
975
                            [% IF ( defaultRefundRule == 'refund' ) %]
976
                            <option value="refund" selected="selected">Refund lost item charge</option>
976
                            <option value="refund" selected="selected">Refund lost item charge</option>
977
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
978
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
979
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
980
                            <option value="0">Leave lost item charge</option>
981
                            [% ELSIF ( defaultRefundRule == 'refund_unpaid' ) %]
982
                            <option value="refund">Refund lost item charge</option>
983
                            <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
977
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
984
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
978
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
985
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
979
                            <option value="0">Leave lost item charge</option>
986
                            <option value="0">Leave lost item charge</option>
980
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
987
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
981
                            <option value="refund">Refund lost item charge</option>
988
                            <option value="refund">Refund lost item charge</option>
989
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
982
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
990
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
983
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
991
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
984
                            <option value="0">Leave lost item charge</option>
992
                            <option value="0">Leave lost item charge</option>
985
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
993
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
986
                            <option value="refund">Refund lost item charge</option>
994
                            <option value="refund">Refund lost item charge</option>
995
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
987
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
996
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
988
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
997
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
989
                            <option value="0">Leave lost item charge</option>
998
                            <option value="0">Leave lost item charge</option>
990
                            [% ELSIF ( defaultRefundRule == 0 ) %]
999
                            [% ELSIF ( defaultRefundRule == 0 ) %]
991
                            <option value="refund">Refund lost item charge</option>
1000
                            <option value="refund">Refund lost item charge</option>
1001
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
992
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1002
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
993
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1003
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
994
                            <option value="0" selected="selected">Leave lost item charge</option>
1004
                            <option value="0" selected="selected">Leave lost item charge</option>
995
                            [% ELSE %]
1005
                            [% ELSE %]
996
                            <option value="refund">Refund lost item charge</option>
1006
                            <option value="refund">Refund lost item charge</option>
1007
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
997
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1008
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
998
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1009
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
999
                            <option value="0">Leave lost item charge</option>
1010
                            <option value="0">Leave lost item charge</option>
Lines 1007-1012 Link Here
1007
                            [% END %]
1018
                            [% END %]
1008
                              [% IF defaultRefundRule == 'refund' %]
1019
                              [% IF defaultRefundRule == 'refund' %]
1009
                                Use default (Refund lost item charge)
1020
                                Use default (Refund lost item charge)
1021
                              [% ELSIF defaultRefundRule == 'refund_unpaid' %]
1022
                                Use default (Refund lost item charge (only if unpaid))
1010
                              [% ELSIF defaultRefundRule == 'charge' %]
1023
                              [% ELSIF defaultRefundRule == 'charge' %]
1011
                                Use default (Refund lost item charge and restore overdue fine)
1024
                                Use default (Refund lost item charge and restore overdue fine)
1012
                              [% ELSIF defaultRefundRule == 'restore' %]
1025
                              [% ELSIF defaultRefundRule == 'restore' %]
Lines 1017-1043 Link Here
1017
                                </option>
1030
                                </option>
1018
                            [% IF ( not refundLostItemFeeRule ) %]
1031
                            [% IF ( not refundLostItemFeeRule ) %]
1019
                                <option value="refund">Refund lost item charge</option>
1032
                                <option value="refund">Refund lost item charge</option>
1033
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1020
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1034
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1021
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1035
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1022
                                <option value="0">Leave lost item charge</option>
1036
                                <option value="0">Leave lost item charge</option>
1023
                            [% ELSE %]
1037
                            [% ELSE %]
1024
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
1038
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
1025
                                <option value="refund" selected="selected">Refund lost item charge</option>
1039
                                <option value="refund" selected="selected">Refund lost item charge</option>
1040
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1026
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1041
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1027
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1042
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1028
                                <option value="0">Leave lost item charge</option>
1043
                                <option value="0">Leave lost item charge</option>
1044
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'refund_unpaid' ) %]
1045
                                <option value="refund">Refund lost item charge</option>
1046
                                <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
1047
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1048
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1049
                                <option value="0">Leave lost item charge</option>
1029
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
1050
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
1030
                                <option value="refund">Refund lost item charge</option>
1051
                                <option value="refund">Refund lost item charge</option>
1052
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1031
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1053
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1032
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1054
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1033
                                <option value="0">Leave lost item charge</option>
1055
                                <option value="0">Leave lost item charge</option>
1034
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
1056
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
1035
                                <option value="refund">Refund lost item charge</option>
1057
                                <option value="refund">Refund lost item charge</option>
1058
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1036
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1059
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1037
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1060
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1038
                                <option value="0">Leave lost item charge</option>
1061
                                <option value="0">Leave lost item charge</option>
1039
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
1062
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
1040
                                <option value="refund">Refund lost item charge</option>
1063
                                <option value="refund">Refund lost item charge</option>
1064
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1041
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1065
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1042
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1066
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1043
                                <option value="0" selected="selected">Leave lost item charge</option>
1067
                                <option value="0" selected="selected">Leave lost item charge</option>
(-)a/t/db_dependent/Circulation.t (-2 / +191 lines)
Lines 3138-3144 subtest 'AddReturn | is_overdue' => sub { Link Here
3138
    };
3138
    };
3139
3139
3140
    subtest 'enh 23091 | Lost item return policies' => sub {
3140
    subtest 'enh 23091 | Lost item return policies' => sub {
3141
        plan tests => 4;
3141
        plan tests => 5;
3142
3142
3143
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
3143
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
3144
3144
Lines 3199-3204 subtest 'AddReturn | is_overdue' => sub { Link Here
3199
            }
3199
            }
3200
        );
3200
        );
3201
3201
3202
        my $branchcode_refund_unpaid =
3203
        $builder->build( { source => 'Branch' } )->{branchcode};
3204
        my $specific_rule_refund_unpaid = $builder->build(
3205
            {
3206
                source => 'CirculationRule',
3207
                value  => {
3208
                    branchcode   => $branchcode_refund_unpaid,
3209
                    categorycode => undef,
3210
                    itemtype     => undef,
3211
                    rule_name    => 'lostreturn',
3212
                    rule_value   => 'refund_unpaid'
3213
                }
3214
            }
3215
        );
3216
3202
        my $replacement_amount = 99.00;
3217
        my $replacement_amount = 99.00;
3203
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
3218
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
3204
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
3219
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
Lines 3209-3214 subtest 'AddReturn | is_overdue' => sub { Link Here
3209
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
3224
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
3210
            undef );
3225
            undef );
3211
3226
3227
        subtest 'lostreturn | refund_unpaid' => sub {
3228
            plan tests => 21;
3229
3230
            t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_refund_unpaid });
3231
3232
            my $item = $builder->build_sample_item(
3233
                {
3234
                    replacementprice => $replacement_amount
3235
                }
3236
            );
3237
3238
            # Issue the item
3239
            my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3240
3241
            # Mark item as lost
3242
            $item->itemlost(3)->store;
3243
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3244
3245
            my $lost_fee_lines = Koha::Account::Lines->search(
3246
                {
3247
                    borrowernumber  => $patron->id,
3248
                    itemnumber      => $item->itemnumber,
3249
                    debit_type_code => 'LOST'
3250
                }
3251
            );
3252
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3253
            my $lost_fee_line = $lost_fee_lines->next;
3254
            is( int($lost_fee_line->amount),
3255
                $replacement_amount, 'The right LOST amount is generated' );
3256
            is( int($lost_fee_line->amountoutstanding),
3257
                $replacement_amount,
3258
                'The right LOST amountoutstanding is generated' );
3259
            is( $lost_fee_line->status, undef, 'The LOST status was not set' );
3260
3261
            is(
3262
                int($patron->account->balance),
3263
                $replacement_amount ,
3264
                "Account balance equals the replacement amount after being charged lost fee when no payments has been made"
3265
            );
3266
3267
            # Return lost item without any payments having been made
3268
            my ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3269
3270
            $lost_fee_line->discard_changes;
3271
3272
            is( int($lost_fee_line->amount), $replacement_amount, 'The LOST amount is left intact' );
3273
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero' );
3274
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set' );
3275
            is(
3276
                int($patron->account->balance),
3277
                0,
3278
                'Account balance should be zero after returning item with lost fee when no payments has been made'
3279
            );
3280
3281
            # Create a second item
3282
            $item = $builder->build_sample_item(
3283
                {
3284
                    replacementprice => $replacement_amount
3285
                }
3286
            );
3287
3288
            # Issue the item
3289
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3290
3291
            # Mark item as lost
3292
            $item->itemlost(3)->store;
3293
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3294
3295
            $lost_fee_lines = Koha::Account::Lines->search(
3296
                {
3297
                    borrowernumber  => $patron->id,
3298
                    itemnumber      => $item->itemnumber,
3299
                    debit_type_code => 'LOST'
3300
                }
3301
            );
3302
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3303
            $lost_fee_line = $lost_fee_lines->next;
3304
3305
            # Make partial payment
3306
            $patron->account->payin_amount({
3307
                type => 'PAYMENT',
3308
                interface => 'intranet',
3309
                payment_type => 'CASH',
3310
                user_id => $patron->borrowernumber,
3311
                amount => 39.00,
3312
                lines => [$lost_fee_line]
3313
            });
3314
3315
            $lost_fee_line->discard_changes;
3316
3317
            is( int($lost_fee_line->amountoutstanding),
3318
                60,
3319
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3320
            );
3321
3322
            is(
3323
                int($patron->account->balance),
3324
                60,
3325
                'Account balance is the expected amount after partial payment of lost fee'
3326
            );
3327
3328
             # Return lost item with partial payment having been made
3329
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3330
3331
            $lost_fee_line->discard_changes;
3332
3333
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with partial payment' );
3334
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item with partial payment' );
3335
            is(
3336
                int($patron->account->balance),
3337
                0,
3338
                'Account balance should be zero after returning item with lost fee when partial payment has been made'
3339
            );
3340
3341
            # Create a third item
3342
            $item = $builder->build_sample_item(
3343
                {
3344
                    replacementprice => $replacement_amount
3345
                }
3346
            );
3347
3348
            # Issue the item
3349
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3350
3351
            # Mark item as lost
3352
            $item->itemlost(3)->store;
3353
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3354
3355
            $lost_fee_lines = Koha::Account::Lines->search(
3356
                {
3357
                    borrowernumber  => $patron->id,
3358
                    itemnumber      => $item->itemnumber,
3359
                    debit_type_code => 'LOST'
3360
                }
3361
            );
3362
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3363
            $lost_fee_line = $lost_fee_lines->next;
3364
3365
            # Make full payment
3366
            $patron->account->payin_amount({
3367
                type => 'PAYMENT',
3368
                interface => 'intranet',
3369
                payment_type => 'CASH',
3370
                user_id => $patron->borrowernumber,
3371
                amount => $replacement_amount,
3372
                lines => [$lost_fee_line]
3373
            });
3374
3375
            $lost_fee_line->discard_changes;
3376
3377
            is( int($lost_fee_line->amountoutstanding),
3378
                0,
3379
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3380
            );
3381
3382
            is(
3383
                int($patron->account->balance),
3384
                0,
3385
                'Account balance is the expected amount after partial payment of lost fee'
3386
            );
3387
3388
             # Return lost item with partial payment having been made
3389
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3390
3391
            $lost_fee_line->discard_changes;
3392
3393
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with full payment' );
3394
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item iwth partial payment' );
3395
            is(
3396
                int($patron->account->balance),
3397
                0,
3398
                'Account balance should be zero after returning item with lost fee when full payment has been made'
3399
            );
3400
        };
3401
3212
        subtest 'lostreturn | false' => sub {
3402
        subtest 'lostreturn | false' => sub {
3213
            plan tests => 12;
3403
            plan tests => 12;
3214
3404
3215
- 

Return to bug 20262