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

(-)a/C4/Accounts.pm (-24 / +36 lines)
Lines 24-30 use C4::Members; Link Here
24
use Koha::Account;
24
use Koha::Account;
25
use Koha::Account::Lines;
25
use Koha::Account::Lines;
26
use Koha::Account::Offsets;
26
use Koha::Account::Offsets;
27
use Koha::CirculationRules;
28
use Koha::Checkouts;
27
use Koha::Items;
29
use Koha::Items;
30
use Koha::Patrons;
28
31
29
use vars qw(@ISA @EXPORT);
32
use vars qw(@ISA @EXPORT);
30
33
Lines 67-78 FIXME : if no replacement price, borrower just doesn't get charged? Link Here
67
70
68
sub chargelostitem {
71
sub chargelostitem {
69
    my $dbh = C4::Context->dbh();
72
    my $dbh = C4::Context->dbh();
70
    my ( $borrowernumber, $itemnumber, $replacementprice, $description ) = @_;
73
    my ( $borrowernumber, $itemnumber, $replacementprice, $description, $opts ) = @_;
74
    $opts ||= {};
75
71
    my $patron = Koha::Patrons->find($borrowernumber);
76
    my $patron = Koha::Patrons->find($borrowernumber);
72
    my $item   = Koha::Items->find($itemnumber);
77
    my $item   = Koha::Items->find($itemnumber);
73
    my $itype  = $item->itemtype;
78
    my $itype  = $item->itemtype;
74
    $replacementprice //= 0;
79
    $replacementprice //= 0;
75
    my $defaultreplacecost = $itype->defaultreplacecost;
80
81
    my $defaultreplacecost        = $itype->defaultreplacecost;
82
    my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost");
83
    my $processingfeenote         = C4::Context->preference("ProcessingFeeNote");
76
84
77
    my $lost_control_pref = C4::Context->preference('LostChargesControl');
85
    my $lost_control_pref = C4::Context->preference('LostChargesControl');
78
    my $lost_control_branch;
86
    my $lost_control_branch;
Lines 87-127 sub chargelostitem { Link Here
87
            : $item->holdingbranch;
95
            : $item->holdingbranch;
88
    }
96
    }
89
97
90
    my $processfee = Koha::CirculationRules->get_effective_rule_value(
98
    my $interface  = $opts->{interface} // C4::Context->interface;
91
        {
99
    my $library_id = defined $opts->{library_id} ? $opts->{library_id} : $lost_control_branch;
92
            rule_name    => "lost_item_processing_fee",
100
93
            categorycode => undef,
101
    my $issue_id = $opts->{issue_id};
94
            itemtype     => $itype->itemtype,
102
    if ( !defined $issue_id ) {
95
            branchcode   => $lost_control_branch
103
        my $checkout = Koha::Checkouts->find( { itemnumber => $itemnumber } );
104
        if ( !$checkout && $item->in_bundle ) {
105
            my $host = $item->bundle_host;
106
            $checkout = $host->checkout;
96
        }
107
        }
97
    ) // 0;
108
        $issue_id = $checkout ? $checkout->issue_id : undef;
98
    my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost");
109
    }
99
    my $processingfeenote         = C4::Context->preference("ProcessingFeeNote");
100
110
101
    if ( $usedefaultreplacementcost && $replacementprice == 0 && $defaultreplacecost ) {
111
    if ( $usedefaultreplacementcost && $replacementprice == 0 && $defaultreplacecost ) {
102
        $replacementprice = $defaultreplacecost;
112
        $replacementprice = $defaultreplacecost;
103
    }
113
    }
104
    my $checkout = Koha::Checkouts->find( { itemnumber => $itemnumber } );
105
    if ( !$checkout && $item->in_bundle ) {
106
        my $host = $item->bundle_host;
107
        $checkout = $host->checkout;
108
    }
109
    my $issue_id = $checkout ? $checkout->issue_id : undef;
110
114
111
    my $account = Koha::Account->new( { patron_id => $borrowernumber } );
115
    my $account = Koha::Account->new( { patron_id => $borrowernumber } );
112
116
113
    # first make sure the borrower hasn't already been charged for this item (for this issuance)
114
    my $existing_charges = $account->lines->search(
117
    my $existing_charges = $account->lines->search(
115
        {
118
        {
116
            itemnumber      => $itemnumber,
119
            item_id         => $itemnumber,
117
            debit_type_code => 'LOST',
120
            debit_type_code => 'LOST',
118
            issue_id        => $issue_id
121
            issue_id        => $issue_id,
119
        }
122
        }
120
    )->count();
123
    )->count();
121
124
122
    # OK, they haven't
125
    # OK, they haven't
123
    unless ($existing_charges) {
126
    unless ($existing_charges) {
124
127
128
        my $processfee = Koha::CirculationRules->get_effective_rule_value(
129
            {
130
                rule_name    => "lost_item_processing_fee",
131
                categorycode => undef,
132
                itemtype     => $itype->itemtype,
133
                branchcode   => $library_id,
134
            }
135
        ) // 0;
136
125
        #add processing fee
137
        #add processing fee
126
        if ( $processfee && $processfee > 0 ) {
138
        if ( $processfee && $processfee > 0 ) {
127
            my $accountline = $account->add_debit(
139
            my $accountline = $account->add_debit(
Lines 131-140 sub chargelostitem { Link Here
131
                    note        => $processingfeenote,
143
                    note        => $processingfeenote,
132
                    user_id     => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
144
                    user_id     => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
133
                    interface   => C4::Context->interface,
145
                    interface   => C4::Context->interface,
134
                    library_id  => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
146
                    library_id  => $library_id,
135
                    type        => 'PROCESSING',
147
                    type        => 'PROCESSING',
136
                    item_id     => $itemnumber,
148
                    item_id     => $itemnumber,
137
                    issue_id    => $issue_id,
149
                    ( defined $issue_id ? ( issue_id => $issue_id ) : () ),
138
                }
150
                }
139
            );
151
            );
140
        }
152
        }
Lines 148-157 sub chargelostitem { Link Here
148
                    note        => undef,
160
                    note        => undef,
149
                    user_id     => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
161
                    user_id     => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
150
                    interface   => C4::Context->interface,
162
                    interface   => C4::Context->interface,
151
                    library_id  => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
163
                    library_id  => $library_id,
152
                    type        => 'LOST',
164
                    type        => 'LOST',
153
                    item_id     => $itemnumber,
165
                    item_id     => $itemnumber,
154
                    issue_id    => $issue_id,
166
                    ( defined $issue_id ? ( issue_id => $issue_id ) : () ),
155
                }
167
                }
156
            );
168
            );
157
        }
169
        }
(-)a/C4/Circulation.pm (-10 / +38 lines)
Lines 46-51 use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue; Link Here
46
use Koha::Biblioitems;
46
use Koha::Biblioitems;
47
use Koha::DateUtils qw( dt_from_string );
47
use Koha::DateUtils qw( dt_from_string );
48
use Koha::Calendar;
48
use Koha::Calendar;
49
use Koha::Checkout;
49
use Koha::Checkouts;
50
use Koha::Checkouts;
50
use Koha::ILL::Requests;
51
use Koha::ILL::Requests;
51
use Koha::Items;
52
use Koha::Items;
Lines 4446-4467 sub LostItem { Link Here
4446
            or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!";    # zero is OK, check defined
4447
            or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!";    # zero is OK, check defined
4447
4448
4448
        if ( C4::Context->preference('WhenLostChargeReplacementFee') ) {
4449
        if ( C4::Context->preference('WhenLostChargeReplacementFee') ) {
4450
            my $desc = sprintf(
4451
                "%s %s %s",
4452
                $issues->{'title'}          || q{},
4453
                $issues->{'barcode'}        || q{},
4454
                $issues->{'itemcallnumber'} || q{},
4455
            );
4456
4457
            my $interface =
4458
                ( $mark_lost_from && $mark_lost_from eq 'cronjob' )
4459
                ? 'cron'
4460
                : C4::Context->interface;
4461
4462
            my $item_obj  = Koha::Items->find($itemnumber);
4463
            my $issue_obj = Koha::Checkouts->search(
4464
                {
4465
                    itemnumber     => $itemnumber,
4466
                    borrowernumber => $borrowernumber,
4467
                }
4468
            )->next;
4469
            my $rule_branch = Koha::Checkout->branch_for_fee_context(
4470
                fee_type => 'LOST',
4471
                patron   => $patron,
4472
                item     => $item_obj,
4473
                issue    => $issue_obj,
4474
            );
4475
            my $issue_id = $issues->{issue_id} // ( $issue_obj ? $issue_obj->issue_id : undef );
4476
4449
            C4::Accounts::chargelostitem(
4477
            C4::Accounts::chargelostitem(
4450
                $borrowernumber,
4478
                $borrowernumber,
4451
                $itemnumber,
4479
                $itemnumber,
4452
                $issues->{'replacementprice'},
4480
                ( ( $issues->{'replacementprice'} // 0 ) + 0 ),
4453
                sprintf(
4481
                $desc,
4454
                    "%s %s %s",
4482
                {
4455
                    $issues->{'title'}          || q{},
4483
                    interface  => $interface,
4456
                    $issues->{'barcode'}        || q{},
4484
                    library_id => $rule_branch,
4457
                    $issues->{'itemcallnumber'} || q{},
4485
                    issue_id   => $issue_id,
4458
                ),
4486
                }
4459
            );
4487
            );
4460
4461
            #FIXME : Should probably have a way to distinguish this from an item that really was returned.
4462
            #warn " $issues->{'borrowernumber'}  /  $itemnumber ";
4463
        }
4488
        }
4464
4489
4490
        #FIXME : Should probably have a way to distinguish this from an item that really was returned.
4491
        #warn " $issues->{'borrowernumber'}  /  $itemnumber ";
4492
4465
        MarkIssueReturned( $borrowernumber, $itemnumber, undef, $patron->privacy, $params ) if $mark_returned;
4493
        MarkIssueReturned( $borrowernumber, $itemnumber, undef, $patron->privacy, $params ) if $mark_returned;
4466
    }
4494
    }
4467
4495
(-)a/C4/Overdues.pm (-2 / +15 lines)
Lines 30-36 use C4::Accounts; Link Here
30
use C4::Context;
30
use C4::Context;
31
use Koha::Account::Lines;
31
use Koha::Account::Lines;
32
use Koha::Account::Offsets;
32
use Koha::Account::Offsets;
33
use Koha::Checkout;
34
use Koha::Checkouts;
33
use Koha::DateUtils qw( output_pref );
35
use Koha::DateUtils qw( output_pref );
36
use Koha::Items;
34
use Koha::Libraries;
37
use Koha::Libraries;
35
use Koha::Recalls;
38
use Koha::Recalls;
36
use Koha::Logger;
39
use Koha::Logger;
Lines 650-656 sub UpdateFine { Link Here
650
            };
653
            };
651
            my $desc = $letter ? $letter->{content} : sprintf( "Item %s - due %s", $itemnum, output_pref($due) );
654
            my $desc = $letter ? $letter->{content} : sprintf( "Item %s - due %s", $itemnum, output_pref($due) );
652
655
653
            my $account = Koha::Account->new( { patron_id => $borrowernumber } );
656
            my $account   = Koha::Account->new( { patron_id => $borrowernumber } );
657
            my $item_obj  = Koha::Items->find($itemnum);
658
            my $issue_obj = Koha::Checkouts->find($issue_id);
659
660
            my $rule_branch = Koha::Checkout->branch_for_fee_context(
661
                fee_type => 'OVERDUE',
662
                patron   => $patron,
663
                item     => $item_obj,
664
                issue    => $issue_obj,
665
            );
666
654
            $accountline = $account->add_debit(
667
            $accountline = $account->add_debit(
655
                {
668
                {
656
                    amount      => $amount,
669
                    amount      => $amount,
Lines 658-664 sub UpdateFine { Link Here
658
                    note        => undef,
671
                    note        => undef,
659
                    user_id     => undef,
672
                    user_id     => undef,
660
                    interface   => C4::Context->interface,
673
                    interface   => C4::Context->interface,
661
                    library_id  => undef,       #FIXME: Should we grab the checkout or circ-control branch here perhaps?
674
                    library_id  => $rule_branch,
662
                    type        => 'OVERDUE',
675
                    type        => 'OVERDUE',
663
                    item_id     => $itemnum,
676
                    item_id     => $itemnum,
664
                    issue_id    => $issue_id,
677
                    issue_id    => $issue_id,
(-)a/Koha/Checkout.pm (+47 lines)
Lines 24-29 use DateTime; Link Here
24
use Try::Tiny qw( catch try );
24
use Try::Tiny qw( catch try );
25
25
26
use C4::Circulation qw( AddRenewal CanBookBeRenewed LostItem MarkIssueReturned );
26
use C4::Circulation qw( AddRenewal CanBookBeRenewed LostItem MarkIssueReturned );
27
use Koha::Checkout;
27
use Koha::Booking;
28
use Koha::Booking;
28
use Koha::Checkouts::Renewals;
29
use Koha::Checkouts::Renewals;
29
use Koha::Checkouts::ReturnClaims;
30
use Koha::Checkouts::ReturnClaims;
Lines 341-346 sub claim_returned { Link Here
341
    };
342
    };
342
}
343
}
343
344
345
=head2 branch_for_fee_context
346
347
my $branchcode = Koha::Checkout->branch_for_fee_context(
348
        fee_type => 'OVERDUE' | 'LOST' | 'PROCESSING',
349
        );
350
351
Determines which branch’s rules should apply to a fee based on system preferences and available context. For LOST/PROCESSING it honors LostChargesControl; for OVERDUE it honors CircControl. It also respects HomeOrHoldingBranch when choosing the item’s branch. Returns a branchcode (string) or undef if it cannot be determined.
352
353
=cut
354
355
sub branch_for_fee_context {
356
    my ( $class, %args ) = @_;
357
358
    my $fee_type = $args{fee_type} // 'OVERDUE';
359
360
    # Choose the controlling preference depending on fee type
361
    my $control_pref =
362
        ( $fee_type eq 'LOST' || $fee_type eq 'PROCESSING' )
363
        ? C4::Context->preference('LostChargesControl')
364
        : C4::Context->preference('CircControl');
365
366
    # Item branch selection (home vs holding)
367
    my $hoh_pref    = C4::Context->preference('HomeOrHoldingBranch') // 'home';
368
    my $use_holding = ( $hoh_pref =~ /holding/i ) ? 1 : 0;
369
370
    # Support Koha objects OR plain hashes
371
    my $patron_branch  = eval { $args{patron}->branchcode }  // ( $args{patron} && $args{patron}->{branchcode} );
372
    my $issuing_branch = eval { $args{issue}->branchcode }   // ( $args{issue}  && $args{issue}->{branchcode} );
373
    my $item_home      = eval { $args{item}->homebranch }    // ( $args{item}   && $args{item}->{homebranch} );
374
    my $item_holding   = eval { $args{item}->holdingbranch } // ( $args{item}   && $args{item}->{holdingbranch} );
375
    my $item_branch    = $use_holding ? ( $item_holding // $item_home ) : $item_home;
376
377
    # Normalize empty strings to undef so // works as intended
378
    for my $ref ( \$patron_branch, \$issuing_branch, \$item_home, \$item_holding, \$item_branch ) {
379
        $$ref = undef if defined $$ref && $$ref eq '';
380
    }
381
382
    # Resolution order depends on controlling pref
383
    my $resolved =
384
          ( defined $control_pref && $control_pref eq 'PatronLibrary' ) ? $patron_branch
385
        : ( defined $control_pref && $control_pref eq 'PickupLibrary' )
386
        ? ( $issuing_branch // $patron_branch // $item_branch )
387
        : $item_branch;    # ItemLibrary (default)
388
    return $resolved;
389
}
390
344
=head2 Internal methods
391
=head2 Internal methods
345
392
346
=head3 _type
393
=head3 _type
(-)a/misc/cronjobs/longoverdue.pl (-2 / +20 lines)
Lines 34-39 use Pod::Usage qw( pod2usage ); Link Here
34
use C4::Circulation qw( LostItem MarkIssueReturned );
34
use C4::Circulation qw( LostItem MarkIssueReturned );
35
use C4::Context;
35
use C4::Context;
36
use C4::Log qw( cronlogaction );
36
use C4::Log qw( cronlogaction );
37
use Koha::Checkout;
38
use Koha::Checkouts;
39
use Koha::Items;
37
use Koha::ItemTypes;
40
use Koha::ItemTypes;
38
use Koha::Patron::Categories;
41
use Koha::Patron::Categories;
39
use Koha::Patrons;
42
use Koha::Patrons;
Lines 522-528 foreach my $startrange ( sort keys %$lost ) { Link Here
522
            if ($confirm) {
525
            if ($confirm) {
523
                Koha::Items->find( $row->{itemnumber} )->itemlost($lostvalue)->store;
526
                Koha::Items->find( $row->{itemnumber} )->itemlost($lostvalue)->store;
524
                if ( $charge && $charge eq $lostvalue ) {
527
                if ( $charge && $charge eq $lostvalue ) {
525
                    LostItem( $row->{'itemnumber'}, 'cronjob', $mark_returned );
528
                    my $patron = Koha::Patrons->find( $row->{borrowernumber} );
529
                    my $item   = Koha::Items->find( $row->{itemnumber} );
530
                    my $issue  = Koha::Checkouts->search(
531
                        {
532
                            itemnumber     => $row->{itemnumber},
533
                            borrowernumber => $row->{borrowernumber},
534
                        }
535
                    )->next;
536
537
                    my $rule_branch = Koha::Checkout->branch_for_fee_context(
538
                        fee_type => 'LOST',
539
                        patron   => $patron,
540
                        item     => $item,
541
                        issue    => $issue,
542
                    );
543
544
                    LostItem( $row->{itemnumber}, 'cronjob', $mark_returned, { library_id => $rule_branch } );
526
                } elsif ($mark_returned) {
545
                } elsif ($mark_returned) {
527
                    $patron ||= Koha::Patrons->find( $row->{borrowernumber} );
546
                    $patron ||= Koha::Patrons->find( $row->{borrowernumber} );
528
                    MarkIssueReturned( $row->{borrowernumber}, $row->{itemnumber}, undef, $patron->privacy );
547
                    MarkIssueReturned( $row->{borrowernumber}, $row->{itemnumber}, undef, $patron->privacy );
529
- 

Return to bug 35612