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

(-)a/C4/Circulation.pm (-6 / +148 lines)
Lines 1530-1535 sub AddIssue { Link Here
1530
                UpdateTotalIssues( $item_object->biblionumber, 1 );
1530
                UpdateTotalIssues( $item_object->biblionumber, 1 );
1531
            }
1531
            }
1532
1532
1533
            # Record if item was lost
1534
            my $was_lost = $item_object->itemlost;
1535
1533
            $item_object->issues( ( $item_object->issues || 0 ) + 1);
1536
            $item_object->issues( ( $item_object->issues || 0 ) + 1);
1534
            $item_object->holdingbranch(C4::Context->userenv->{'branch'});
1537
            $item_object->holdingbranch(C4::Context->userenv->{'branch'});
1535
            $item_object->itemlost(0);
1538
            $item_object->itemlost(0);
Lines 1538-1543 sub AddIssue { Link Here
1538
            $item_object->datelastseen( dt_from_string()->ymd() );
1541
            $item_object->datelastseen( dt_from_string()->ymd() );
1539
            $item_object->store({log_action => 0});
1542
            $item_object->store({log_action => 0});
1540
1543
1544
            # If the item was lost, it has now been found, restore/charge the overdue if necessary
1545
            if ($was_lost) {
1546
                my $lostreturn_policy =
1547
                  Koha::CirculationRules->get_lostreturn_policy(
1548
                    {
1549
                        return_branch => C4::Context->userenv->{branch},
1550
                        item          => $item_object
1551
                    }
1552
                  );
1553
1554
                if ($lostreturn_policy) {
1555
                    if ( $lostreturn_policy eq 'charge' ) {
1556
                        $actualissue //= Koha::Old::Checkouts->search(
1557
                            { itemnumber => $item_unblessed->{itemnumber} },
1558
                            {
1559
                                order_by => { '-desc' => 'returndate' },
1560
                                rows     => 1
1561
                            }
1562
                        )->single;
1563
                        unless ( exists( $borrower->{branchcode} ) ) {
1564
                            my $patron = $actualissue->patron;
1565
                            $borrower = $patron->unblessed;
1566
                        }
1567
                        _CalculateAndUpdateFine(
1568
                            {
1569
                                issue       => $actualissue,
1570
                                item        => $item_unblessed,
1571
                                borrower    => $borrower,
1572
                                return_date => $issuedate
1573
                            }
1574
                        );
1575
                        _FixOverduesOnReturn( $borrower->{borrowernumber},
1576
                            $item_object->itemnumber, undef, 'RENEWED' );
1577
                    }
1578
                    elsif ( $lostreturn_policy eq 'restore' ) {
1579
                        _RestoreOverdueForLostAndFound(
1580
                            $item_object->itemnumber );
1581
                    }
1582
1583
                    if ( C4::Context->preference('AccountAutoReconcile') ) {
1584
                        $account->reconcile_balance;
1585
                    }
1586
                }
1587
1588
            }
1589
1541
            # If it costs to borrow this book, charge it to the patron's account.
1590
            # If it costs to borrow this book, charge it to the patron's account.
1542
            my ( $charge, $itemtype ) = GetIssuingCharges( $item_object->itemnumber, $borrower->{'borrowernumber'} );
1591
            my ( $charge, $itemtype ) = GetIssuingCharges( $item_object->itemnumber, $borrower->{'borrowernumber'} );
1543
            if ( $charge && $charge > 0 ) {
1592
            if ( $charge && $charge > 0 ) {
Lines 2048-2053 sub AddReturn { Link Here
2048
        $messages->{'WasLost'} = 1;
2097
        $messages->{'WasLost'} = 1;
2049
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2098
        unless ( C4::Context->preference("BlockReturnOfLostItems") ) {
2050
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2099
            $messages->{'LostItemFeeRefunded'} = $updated_item->{_refunded};
2100
2101
            my $lostreturn_policy =
2102
              Koha::CirculationRules->get_lostreturn_policy(
2103
                {
2104
                    return_branch => C4::Context->userenv->{branch},
2105
                    item          => $updated_item
2106
                }
2107
              );
2108
2109
            if ($lostreturn_policy) {
2110
                if ( $lostreturn_policy eq 'charge' ) {
2111
                    $issue //= Koha::Old::Checkouts->search(
2112
                        { itemnumber => $item->itemnumber },
2113
                        { order_by   => { '-desc' => 'returndate' }, rows => 1 }
2114
                    )->single;
2115
                    unless (exists($patron_unblessed->{branchcode})) {
2116
                        my $patron = $issue->patron;
2117
                        $patron_unblessed = $patron->unblessed;
2118
                    }
2119
                    _CalculateAndUpdateFine(
2120
                        {
2121
                            issue       => $issue,
2122
                            item        => $item->unblessed,
2123
                            borrower    => $patron_unblessed,
2124
                            return_date => $return_date
2125
                        }
2126
                    );
2127
                    _FixOverduesOnReturn( $patron_unblessed->{borrowernumber},
2128
                        $item->itemnumber, undef, 'RETURNED' );
2129
                    $messages->{'LostItemFeeCharged'} = 1;
2130
                }
2131
                elsif ( $lostreturn_policy eq 'restore' ) {
2132
                    _RestoreOverdueForLostAndFound( $item->itemnumber );
2133
                    $messages->{'LostItemFeeRestored'} = 1;
2134
                }
2135
            }
2051
        }
2136
        }
2052
    }
2137
    }
2053
2138
Lines 2477-2482 sub _FixOverduesOnReturn { Link Here
2477
            my $amountoutstanding = $accountline->amountoutstanding;
2562
            my $amountoutstanding = $accountline->amountoutstanding;
2478
            if ( $accountline->amount == 0 && $payments->count == 0 ) {
2563
            if ( $accountline->amount == 0 && $payments->count == 0 ) {
2479
                $accountline->delete;
2564
                $accountline->delete;
2565
                return 0; # no warning, we've just removed a zero value fine (backdated return)
2480
            } elsif ($exemptfine && ($amountoutstanding != 0)) {
2566
            } elsif ($exemptfine && ($amountoutstanding != 0)) {
2481
                my $account = Koha::Account->new({patron_id => $borrowernumber});
2567
                my $account = Koha::Account->new({patron_id => $borrowernumber});
2482
                my $credit = $account->add_credit(
2568
                my $credit = $account->add_credit(
Lines 2495-2508 sub _FixOverduesOnReturn { Link Here
2495
                if (C4::Context->preference("FinesLog")) {
2581
                if (C4::Context->preference("FinesLog")) {
2496
                    &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
2582
                    &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
2497
                }
2583
                }
2584
            }
2498
2585
2499
                $accountline->status('FORGIVEN');
2586
            $accountline->status($status);
2500
                $accountline->store();
2587
            return $accountline->store();
2501
            } else {
2588
        }
2502
                $accountline->status($status);
2589
    );
2503
                $accountline->store();
2504
2590
2505
            }
2591
    return $result;
2592
}
2593
2594
=head2 _RestoreOverdueForLostAndFound
2595
2596
   &_RestoreOverdueForLostAndFound( $itemnumber );
2597
2598
C<$itemnumber> itemnumber
2599
2600
Internal function
2601
2602
=cut
2603
2604
sub _RestoreOverdueForLostAndFound {
2605
    my ( $item ) = @_;
2606
2607
    unless( $item ) {
2608
        warn "_RestoreOverdueForLostAndFound() not supplied valid itemnumber";
2609
        return;
2610
    }
2611
2612
    my $schema = Koha::Database->schema;
2613
2614
    my $result = $schema->txn_do(
2615
        sub {
2616
            # check for lost overdue fine
2617
            my $accountlines = Koha::Account::Lines->search(
2618
                {
2619
                    itemnumber      => $item,
2620
                    debit_type_code => 'OVERDUE',
2621
                    status          => 'LOST'
2622
                },
2623
                {
2624
                    order_by => { '-desc' => 'date' },
2625
                    rows     => 1
2626
                }
2627
            );
2628
            return 0 unless $accountlines->count; # no warning, there's just nothing to fix
2629
2630
            # Update status of fine
2631
            my $overdue = $accountlines->next;
2632
            $overdue->status('RETURNED')->store();
2633
2634
            # Find related forgive credit
2635
            my $refunds = $overdue->credits(
2636
                {
2637
                    credit_type_code => 'FORGIVEN',
2638
                    itemnumber       => $item,
2639
                    status           => [ { '!=' => 'VOID' }, undef ]
2640
                },
2641
                { order_by => { '-desc' => 'date' }, rows => 1 }
2642
            );
2643
            return 0 unless $refunds->count; # no warning, there's just nothing to fix
2644
2645
            # Revert the forgive credit
2646
            my $refund = $refunds->next;
2647
            return $refund->void();
2506
        }
2648
        }
2507
    );
2649
    );
2508
2650
(-)a/Koha/CirculationRules.pm (-4 / +15 lines)
Lines 46-52 Any attempt to set a rule with a nonsensical scope (for instance, setting the C< Link Here
46
=cut
46
=cut
47
47
48
our $RULE_KINDS = {
48
our $RULE_KINDS = {
49
    refund => {
49
    lostreturn => {
50
        scope => [ 'branchcode' ],
50
        scope => [ 'branchcode' ],
51
    },
51
    },
52
52
Lines 433-439 sub get_onshelfholds_policy { Link Here
433
433
434
=head3 get_lostreturn_policy
434
=head3 get_lostreturn_policy
435
435
436
  my $refund = Koha::CirculationRules->get_lostreturn_policy( { return_branch => $return_branch, item => $item } );
436
  my $lostrefund_policy = Koha::CirculationRules->get_lostreturn_policy( { return_branch => $return_branch, item => $item } );
437
438
Return values are:
439
440
=over 2
441
442
=item 0 - Do not refund
443
=item refund - Refund the lost item charge
444
=item restore - Refund the lost item charge and restore the original overdue fine
445
=item charge - Refund the lost item charge and charge a new overdue fine
446
447
=back
437
448
438
=cut
449
=cut
439
450
Lines 454-464 sub get_lostreturn_policy { Link Here
454
    my $rule = Koha::CirculationRules->get_effective_rule(
465
    my $rule = Koha::CirculationRules->get_effective_rule(
455
        {
466
        {
456
            branchcode => $branch,
467
            branchcode => $branch,
457
            rule_name  => 'refund',
468
            rule_name  => 'lostreturn',
458
        }
469
        }
459
    );
470
    );
460
471
461
    return $rule ? $rule->rule_value : 1;
472
    return $rule ? $rule->rule_value : 'refund';
462
}
473
}
463
474
464
=head3 article_requestable_rules
475
=head3 article_requestable_rules
(-)a/admin/smart-rules.pl (-8 / +8 lines)
Lines 517-532 elsif ($op eq "add-branch-item") { Link Here
517
}
517
}
518
elsif ( $op eq 'mod-refund-lost-item-fee-rule' ) {
518
elsif ( $op eq 'mod-refund-lost-item-fee-rule' ) {
519
519
520
    my $refund = $input->param('refund');
520
    my $lostreturn = $input->param('lostreturn');
521
521
522
    if ( $refund eq '*' ) {
522
    if ( $lostreturn eq '*' ) {
523
        if ( $branch ne '*' ) {
523
        if ( $branch ne '*' ) {
524
            # only do something for $refund eq '*' if branch-specific
524
            # only do something for $lostreturn eq '*' if branch-specific
525
            Koha::CirculationRules->set_rules(
525
            Koha::CirculationRules->set_rules(
526
                {
526
                {
527
                    branchcode   => $branch,
527
                    branchcode   => $branch,
528
                    rules        => {
528
                    rules        => {
529
                        refund => undef
529
                        lostreturn => undef
530
                    }
530
                    }
531
                }
531
                }
532
            );
532
            );
Lines 536-553 elsif ( $op eq 'mod-refund-lost-item-fee-rule' ) { Link Here
536
            {
536
            {
537
                branchcode   => $branch,
537
                branchcode   => $branch,
538
                rules        => {
538
                rules        => {
539
                    refund => $refund
539
                    lostreturn => $lostreturn
540
                }
540
                }
541
            }
541
            }
542
        );
542
        );
543
    }
543
    }
544
}
544
}
545
545
546
my $refundLostItemFeeRule = Koha::CirculationRules->find({ branchcode => ($branch eq '*') ? undef : $branch, rule_name => 'refund' });
546
my $refundLostItemFeeRule = Koha::CirculationRules->find({ branchcode => ($branch eq '*') ? undef : $branch, rule_name => 'lostreturn' });
547
my $defaultLostItemFeeRule = Koha::CirculationRules->find({ branchcode => undef, rule_name => 'refund' });
547
my $defaultLostItemFeeRule = Koha::CirculationRules->find({ branchcode => undef, rule_name => 'lostreturn' });
548
$template->param(
548
$template->param(
549
    refundLostItemFeeRule => $refundLostItemFeeRule,
549
    refundLostItemFeeRule => $refundLostItemFeeRule,
550
    defaultRefundRule     => $defaultLostItemFeeRule ? $defaultLostItemFeeRule->rule_value : 1
550
    defaultRefundRule     => $defaultLostItemFeeRule ? $defaultLostItemFeeRule->rule_value : 'refund'
551
);
551
);
552
552
553
my $patron_categories = Koha::Patron::Categories->search({}, { order_by => ['description'] });
553
my $patron_categories = Koha::Patron::Categories->search({}, { order_by => ['description'] });
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-32 / +56 lines)
Lines 762-784 Link Here
762
                </tr>
762
                </tr>
763
                <tr>
763
                <tr>
764
                    <td>
764
                    <td>
765
                        <select name="refund">
765
                        <select name="lostreturn">
766
                          [%# Default branch %]
766
                          [%# Default branch %]
767
                          [% IF ( current_branch == '*' ) %]
767
                          [% IF ( current_branch == '*' ) %]
768
                            [% IF ( defaultRefundRule ) %]
768
                            [% IF ( defaultRefundRule == 'refund' ) %]
769
                            <option value="1" selected="selected">
769
                            <option value="refund" selected="selected">Refund lost item charge</option>
770
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
771
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
772
                            <option value="0">Leave lost item charge</option>
773
                            [% ELSIF ( defaultRefundRule == 'charge' ) %]
774
                            <option value="refund">Refund lost item charge</option>
775
                            <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
776
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
777
                            <option value="0">Leave lost item charge</option>
778
                            [% ELSIF ( defaultRefundRule == 'restore' ) %]
779
                            <option value="refund">Refund lost item charge</option>
780
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
781
                            <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
782
                            <option value="0">Leave lost item charge</option>
783
                            [% ELSIF ( defaultRefundRule == 0 ) %]
784
                            <option value="refund">Refund lost item charge</option>
785
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
786
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
787
                            <option value="0" selected="selected">Leave lost item charge</option>
770
                            [% ELSE %]
788
                            [% ELSE %]
771
                            <option value="1">
789
                            <option value="refund">Refund lost item charge</option>
790
                            <option value="charge">Refund lost item charge and charge new overdue fine</option>
791
                            <option value="restore">Refund lost item charge and restore overdue fine</option>
792
                            <option value="0">Leave lost item charge</option>
772
                            [% END %]
793
                            [% END %]
773
                                Yes
774
                            </option>
775
                            [% IF ( not defaultRefundRule ) %]
776
                            <option value="0" selected="selected">
777
                            [% ELSE %]
778
                            <option value="0">
779
                            [% END %]
780
                                No
781
                            </option>
782
                          [% ELSE %]
794
                          [% ELSE %]
783
                          [%# Branch-specific %]
795
                          [%# Branch-specific %]
784
                            [% IF ( not refundLostItemFeeRule ) %]
796
                            [% IF ( not refundLostItemFeeRule ) %]
Lines 786-815 Link Here
786
                            [% ELSE %]
798
                            [% ELSE %]
787
                                <option value="*">
799
                                <option value="*">
788
                            [% END %]
800
                            [% END %]
789
                              [% IF defaultRefundRule %]
801
                              [% IF defaultRefundRule == 'refund' %]
790
                                Use default (Yes)
802
                                Use default (Refund lost item charge)
803
                              [% ELSIF defaultRefundRule == 'charge' %]
804
                                Use default (Refund lost item charge and restore overdue fine)
805
                              [% ELSIF defaultRefundRule == 'restore' %]
806
                                Use default (Refund lost item charge and charge new overdue fine)
791
                              [% ELSE %]
807
                              [% ELSE %]
792
                                Use default (No)
808
                                Use default (Leave lost item charge)
793
                              [% END %]
809
                              [% END %]
794
                                </option>
810
                                </option>
795
                            [% IF ( not refundLostItemFeeRule ) %]
811
                            [% IF ( not refundLostItemFeeRule ) %]
796
                                <option value="1">Yes</option>
812
                                <option value="refund">Refund lost item charge</option>
797
                                <option value="0">No</option>
813
                                <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>
815
                                <option value="0">Leave lost item charge</option>
798
                            [% ELSE %]
816
                            [% ELSE %]
799
                                [% IF ( refundLostItemFeeRule.rule_value ) %]
817
                                [% IF ( refundLostItemFeeRule.rule_value == 'refund' ) %]
800
                                <option value="1" selected="selected">
818
                                <option value="refund" selected="selected">Refund lost item charge</option>
801
                                [% ELSE %]
819
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
802
                                <option value="1">
820
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
821
                                <option value="0">Leave lost item charge</option>
822
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'charge' ) %]
823
                                <option value="refund">Refund lost item charge</option>
824
                                <option value="charge" selected="selected">Refund lost item charge and charge new overdue fine</option>
825
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
826
                                <option value="0">Leave lost item charge</option>
827
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 'restore' ) %]
828
                                <option value="refund">Refund lost item charge</option>
829
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
830
                                <option value="restore" selected="selected">Refund lost item charge and restore overdue fine</option>
831
                                <option value="0">Leave lost item charge</option>
832
                                [% ELSIF ( refundLostItemFeeRule.rule_value == 0 ) %]
833
                                <option value="refund">Refund lost item charge</option>
834
                                <option value="charge">Refund lost item charge and charge new overdue fine</option>
835
                                <option value="restore">Refund lost item charge and restore overdue fine</option>
836
                                <option value="0" selected="selected">Leave lost item charge</option>
803
                                [% END %]
837
                                [% END %]
804
                                    Yes
805
                                </option>
806
                                [% IF ( not refundLostItemFeeRule.rule_value ) %]
807
                                <option value="0" selected="selected">
808
                                [% ELSE %]
809
                                <option value="0">
810
                                [% END %]
811
                                    No
812
                                </option>
813
                            [% END %]
838
                            [% END %]
814
                          [% END %]
839
                          [% END %]
815
                        </select>
840
                        </select>
816
- 

Return to bug 23091