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

(-)a/Koha/Item.pm (-8 / +22 lines)
Lines 1190-1203 sub _set_found_trigger { Link Here
1190
            if ( $patron ) {
1190
            if ( $patron ) {
1191
1191
1192
                my $account = $patron->account;
1192
                my $account = $patron->account;
1193
                my $total_to_refund = 0;
1194
1193
1195
                # Use cases
1194
                # Credit outstanding amount
1196
                if ( $lost_charge->amount > $lost_charge->amountoutstanding ) {
1195
                my $credit_total = $lost_charge->amountoutstanding;
1197
1196
1197
                # Use cases
1198
                if (
1199
                    $lost_charge->amount > $lost_charge->amountoutstanding &&
1200
                    $lostreturn_policy ne "refund_unpaid"
1201
                ) {
1198
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1202
                    # some amount has been cancelled. collect the offsets that are not writeoffs
1199
                    # this works because the only way to subtract from this kind of a debt is
1203
                    # this works because the only way to subtract from this kind of a debt is
1200
                    # using the UI buttons 'Pay' and 'Write off'
1204
                    # using the UI buttons 'Pay' and 'Write off'
1205
1206
                    # We don't credit any payments if return policy is
1207
                    # "refund_unpaid"
1208
                    #
1209
                    # In that case only unpaid/outstanding amount
1210
                    # will be credited wich settles the debt without
1211
                    # creating extra credits
1212
1201
                    my $credit_offsets = $lost_charge->debit_offsets(
1213
                    my $credit_offsets = $lost_charge->debit_offsets(
1202
                        {
1214
                        {
1203
                            'credit_id'               => { '!=' => undef },
1215
                            'credit_id'               => { '!=' => undef },
Lines 1206-1218 sub _set_found_trigger { Link Here
1206
                        { join => 'credit' }
1218
                        { join => 'credit' }
1207
                    );
1219
                    );
1208
1220
1209
                    $total_to_refund = ( $credit_offsets->count > 0 )
1221
                    my $total_to_refund = ( $credit_offsets->count > 0 ) ?
1210
                      ? $credit_offsets->total * -1    # credits are negative on the DB
1222
                        # credits are negative on the DB
1211
                      : 0;
1223
                        $credit_offsets->total * -1 :
1224
                        0;
1225
                    # Credit the outstanding amount, then add what has been
1226
                    # paid to create a net credit for this amount
1227
                    $credit_total += $total_to_refund;
1212
                }
1228
                }
1213
1229
1214
                my $credit_total = $lost_charge->amountoutstanding + $total_to_refund;
1215
1216
                my $credit;
1230
                my $credit;
1217
                if ( $credit_total > 0 ) {
1231
                if ( $credit_total > 0 ) {
1218
                    my $branchcode =
1232
                    my $branchcode =
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (+24 lines)
Lines 1080-1105 Link Here
1080
                          [% IF ( current_branch == '*' ) %]
1080
                          [% IF ( current_branch == '*' ) %]
1081
                            [% IF ( defaultRefundRule == 'refund' ) %]
1081
                            [% IF ( defaultRefundRule == 'refund' ) %]
1082
                            <option value="refund" selected="selected">Refund lost item charge</option>
1082
                            <option value="refund" selected="selected">Refund lost item charge</option>
1083
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1084
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1085
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1086
                            <option value="0">Leave lost item charge</option>
1087
                            [% ELSIF ( defaultRefundRule == 'refund_unpaid' ) %]
1088
                            <option value="refund">Refund lost item charge</option>
1089
                            <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
1083
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1090
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1084
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1091
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1085
                            <option value="0">Leave lost item charge</option>
1092
                            <option value="0">Leave lost item charge</option>
1086
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
1093
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
1087
                            <option value="refund">Refund lost item charge</option>
1094
                            <option value="refund">Refund lost item charge</option>
1095
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1088
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1096
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1089
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1097
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1090
                            <option value="0">Leave lost item charge</option>
1098
                            <option value="0">Leave lost item charge</option>
1091
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
1099
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
1092
                            <option value="refund">Refund lost item charge</option>
1100
                            <option value="refund">Refund lost item charge</option>
1101
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1093
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1102
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1094
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1103
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1095
                            <option value="0">Leave lost item charge</option>
1104
                            <option value="0">Leave lost item charge</option>
1096
                            [% ELSIF ( defaultRefundRule == 0 ) %]
1105
                            [% ELSIF ( defaultRefundRule == 0 ) %]
1097
                            <option value="refund">Refund lost item charge</option>
1106
                            <option value="refund">Refund lost item charge</option>
1107
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1098
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1108
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1099
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1109
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1100
                            <option value="0" selected="selected">Leave lost item charge</option>
1110
                            <option value="0" selected="selected">Leave lost item charge</option>
1101
                            [% ELSE %]
1111
                            [% ELSE %]
1102
                            <option value="refund">Refund lost item charge</option>
1112
                            <option value="refund">Refund lost item charge</option>
1113
                            <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1103
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1114
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
1104
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1115
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
1105
                            <option value="0">Leave lost item charge</option>
1116
                            <option value="0">Leave lost item charge</option>
Lines 1113-1118 Link Here
1113
                            [% END %]
1124
                            [% END %]
1114
                              [% IF defaultRefundRule == 'refund' %]
1125
                              [% IF defaultRefundRule == 'refund' %]
1115
                                <span>Use default (Refund lost item charge)</span>
1126
                                <span>Use default (Refund lost item charge)</span>
1127
                              [% ELSIF defaultRefundRule == 'refund_unpaid' %]
1128
                                Use default (Refund lost item charge (only if unpaid))
1116
                              [% ELSIF defaultRefundRule == 'charge' %]
1129
                              [% ELSIF defaultRefundRule == 'charge' %]
1117
                                <span>Use default (Refund lost item charge and charge new overdue fine)</span>
1130
                                <span>Use default (Refund lost item charge and charge new overdue fine)</span>
1118
                              [% ELSIF defaultRefundRule == 'restore' %]
1131
                              [% ELSIF defaultRefundRule == 'restore' %]
Lines 1123-1149 Link Here
1123
                                </option>
1136
                                </option>
1124
                            [% IF ( not refundLostItemFeeRule ) %]
1137
                            [% IF ( not refundLostItemFeeRule ) %]
1125
                                <option value="refund">Refund lost item charge</option>
1138
                                <option value="refund">Refund lost item charge</option>
1139
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1126
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1140
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1127
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1141
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1128
                                <option value="0">Leave lost item charge</option>
1142
                                <option value="0">Leave lost item charge</option>
1129
                            [% ELSE %]
1143
                            [% ELSE %]
1130
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
1144
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
1131
                                <option value="refund" selected="selected">Refund lost item charge</option>
1145
                                <option value="refund" selected="selected">Refund lost item charge</option>
1146
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1132
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1147
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1133
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1148
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1134
                                <option value="0">Leave lost item charge</option>
1149
                                <option value="0">Leave lost item charge</option>
1150
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'refund_unpaid' ) %]
1151
                                <option value="refund">Refund lost item charge</option>
1152
                                <option value="refund_unpaid" selected="selected">Refund lost item charge (only if unpaid)</option>
1153
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1154
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1155
                                <option value="0">Leave lost item charge</option>
1135
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
1156
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
1136
                                <option value="refund">Refund lost item charge</option>
1157
                                <option value="refund">Refund lost item charge</option>
1158
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1137
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1159
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
1138
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1160
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1139
                                <option value="0">Leave lost item charge</option>
1161
                                <option value="0">Leave lost item charge</option>
1140
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
1162
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
1141
                                <option value="refund">Refund lost item charge</option>
1163
                                <option value="refund">Refund lost item charge</option>
1164
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1142
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1165
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1143
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1166
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
1144
                                <option value="0">Leave lost item charge</option>
1167
                                <option value="0">Leave lost item charge</option>
1145
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
1168
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
1146
                                <option value="refund">Refund lost item charge</option>
1169
                                <option value="refund">Refund lost item charge</option>
1170
                                <option value="refund_unpaid">Refund lost item charge (only if unpaid)</option>
1147
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1171
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
1148
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1172
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
1149
                                <option value="0" selected="selected">Leave lost item charge</option>
1173
                                <option value="0" selected="selected">Leave lost item charge</option>
(-)a/t/db_dependent/Circulation.t (-2 / +191 lines)
Lines 3191-3197 subtest 'AddReturn | is_overdue' => sub { Link Here
3191
    };
3191
    };
3192
3192
3193
    subtest 'enh 23091 | Lost item return policies' => sub {
3193
    subtest 'enh 23091 | Lost item return policies' => sub {
3194
        plan tests => 4;
3194
        plan tests => 5;
3195
3195
3196
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
3196
        my $manager = $builder->build_object({ class => "Koha::Patrons" });
3197
3197
Lines 3252-3257 subtest 'AddReturn | is_overdue' => sub { Link Here
3252
            }
3252
            }
3253
        );
3253
        );
3254
3254
3255
        my $branchcode_refund_unpaid =
3256
        $builder->build( { source => 'Branch' } )->{branchcode};
3257
        my $specific_rule_refund_unpaid = $builder->build(
3258
            {
3259
                source => 'CirculationRule',
3260
                value  => {
3261
                    branchcode   => $branchcode_refund_unpaid,
3262
                    categorycode => undef,
3263
                    itemtype     => undef,
3264
                    rule_name    => 'lostreturn',
3265
                    rule_value   => 'refund_unpaid'
3266
                }
3267
            }
3268
        );
3269
3255
        my $replacement_amount = 99.00;
3270
        my $replacement_amount = 99.00;
3256
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
3271
        t::lib::Mocks::mock_preference( 'AllowReturnToBranch', 'anywhere' );
3257
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
3272
        t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
Lines 3262-3267 subtest 'AddReturn | is_overdue' => sub { Link Here
3262
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
3277
        t::lib::Mocks::mock_preference( 'NoRefundOnLostReturnedItemsAge',
3263
            undef );
3278
            undef );
3264
3279
3280
        subtest 'lostreturn | refund_unpaid' => sub {
3281
            plan tests => 21;
3282
3283
            t::lib::Mocks::mock_userenv({ patron => $manager, branchcode => $branchcode_refund_unpaid });
3284
3285
            my $item = $builder->build_sample_item(
3286
                {
3287
                    replacementprice => $replacement_amount
3288
                }
3289
            );
3290
3291
            # Issue the item
3292
            my $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3293
3294
            # Mark item as lost
3295
            $item->itemlost(3)->store;
3296
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3297
3298
            my $lost_fee_lines = Koha::Account::Lines->search(
3299
                {
3300
                    borrowernumber  => $patron->id,
3301
                    itemnumber      => $item->itemnumber,
3302
                    debit_type_code => 'LOST'
3303
                }
3304
            );
3305
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3306
            my $lost_fee_line = $lost_fee_lines->next;
3307
            is( int($lost_fee_line->amount),
3308
                $replacement_amount, 'The right LOST amount is generated' );
3309
            is( int($lost_fee_line->amountoutstanding),
3310
                $replacement_amount,
3311
                'The right LOST amountoutstanding is generated' );
3312
            is( $lost_fee_line->status, undef, 'The LOST status was not set' );
3313
3314
            is(
3315
                int($patron->account->balance),
3316
                $replacement_amount ,
3317
                "Account balance equals the replacement amount after being charged lost fee when no payments has been made"
3318
            );
3319
3320
            # Return lost item without any payments having been made
3321
            my ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3322
3323
            $lost_fee_line->discard_changes;
3324
3325
            is( int($lost_fee_line->amount), $replacement_amount, 'The LOST amount is left intact' );
3326
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero' );
3327
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set' );
3328
            is(
3329
                int($patron->account->balance),
3330
                0,
3331
                'Account balance should be zero after returning item with lost fee when no payments has been made'
3332
            );
3333
3334
            # Create a second item
3335
            $item = $builder->build_sample_item(
3336
                {
3337
                    replacementprice => $replacement_amount
3338
                }
3339
            );
3340
3341
            # Issue the item
3342
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3343
3344
            # Mark item as lost
3345
            $item->itemlost(3)->store;
3346
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3347
3348
            $lost_fee_lines = Koha::Account::Lines->search(
3349
                {
3350
                    borrowernumber  => $patron->id,
3351
                    itemnumber      => $item->itemnumber,
3352
                    debit_type_code => 'LOST'
3353
                }
3354
            );
3355
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3356
            $lost_fee_line = $lost_fee_lines->next;
3357
3358
            # Make partial payment
3359
            $patron->account->payin_amount({
3360
                type => 'PAYMENT',
3361
                interface => 'intranet',
3362
                payment_type => 'CASH',
3363
                user_id => $patron->borrowernumber,
3364
                amount => 39.00,
3365
                lines => [$lost_fee_line]
3366
            });
3367
3368
            $lost_fee_line->discard_changes;
3369
3370
            is( int($lost_fee_line->amountoutstanding),
3371
                60,
3372
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3373
            );
3374
3375
            is(
3376
                int($patron->account->balance),
3377
                60,
3378
                'Account balance is the expected amount after partial payment of lost fee'
3379
            );
3380
3381
             # Return lost item with partial payment having been made
3382
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3383
3384
            $lost_fee_line->discard_changes;
3385
3386
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with partial payment' );
3387
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item with partial payment' );
3388
            is(
3389
                int($patron->account->balance),
3390
                0,
3391
                'Account balance should be zero after returning item with lost fee when partial payment has been made'
3392
            );
3393
3394
            # Create a third item
3395
            $item = $builder->build_sample_item(
3396
                {
3397
                    replacementprice => $replacement_amount
3398
                }
3399
            );
3400
3401
            # Issue the item
3402
            $issue = C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
3403
3404
            # Mark item as lost
3405
            $item->itemlost(3)->store;
3406
            C4::Circulation::LostItem( $item->itemnumber, 1 );
3407
3408
            $lost_fee_lines = Koha::Account::Lines->search(
3409
                {
3410
                    borrowernumber  => $patron->id,
3411
                    itemnumber      => $item->itemnumber,
3412
                    debit_type_code => 'LOST'
3413
                }
3414
            );
3415
            is( $lost_fee_lines->count, 1, 'Lost item fee produced' );
3416
            $lost_fee_line = $lost_fee_lines->next;
3417
3418
            # Make full payment
3419
            $patron->account->payin_amount({
3420
                type => 'PAYMENT',
3421
                interface => 'intranet',
3422
                payment_type => 'CASH',
3423
                user_id => $patron->borrowernumber,
3424
                amount => $replacement_amount,
3425
                lines => [$lost_fee_line]
3426
            });
3427
3428
            $lost_fee_line->discard_changes;
3429
3430
            is( int($lost_fee_line->amountoutstanding),
3431
                0,
3432
                'The LOST amountoutstanding is the expected amount after partial payment of lost fee'
3433
            );
3434
3435
            is(
3436
                int($patron->account->balance),
3437
                0,
3438
                'Account balance is the expected amount after partial payment of lost fee'
3439
            );
3440
3441
             # Return lost item with partial payment having been made
3442
            ( $returned, $message ) = AddReturn( $item->barcode, $branchcode_refund_unpaid );
3443
3444
            $lost_fee_line->discard_changes;
3445
3446
            is( int($lost_fee_line->amountoutstanding) , 0, 'The LOST amountoutstanding is zero after returning lost item with full payment' );
3447
            is( $lost_fee_line->status, 'FOUND', 'The FOUND status was set for lost item iwth partial payment' );
3448
            is(
3449
                int($patron->account->balance),
3450
                0,
3451
                'Account balance should be zero after returning item with lost fee when full payment has been made'
3452
            );
3453
        };
3454
3265
        subtest 'lostreturn | false' => sub {
3455
        subtest 'lostreturn | false' => sub {
3266
            plan tests => 12;
3456
            plan tests => 12;
3267
3457
3268
- 

Return to bug 20262