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

(-)a/Koha/Account.pm (-6 / +20 lines)
Lines 273-279 sub pay { Link Here
273
    # If we have overdue unreturned items that have had payments made
273
    # If we have overdue unreturned items that have had payments made
274
    # against them, check whether the balance on those items is now zero
274
    # against them, check whether the balance on those items is now zero
275
    # and, if the syspref is set, renew them
275
    # and, if the syspref is set, renew them
276
    _maybe_renew($overdue_unreturned, $self->{patron_id});
276
    my $renew_result = _maybe_renew($overdue_unreturned, $self->{patron_id});
277
277
278
    if ( C4::Context->preference("FinesLog") ) {
278
    if ( C4::Context->preference("FinesLog") ) {
279
        logaction(
279
        logaction(
Lines 322-328 sub pay { Link Here
322
        }
322
        }
323
    }
323
    }
324
324
325
    return $payment->id;
325
    return { payment_id => $payment->id, renew_result => $renew_result };
326
}
326
}
327
327
328
=head3 add_credit
328
=head3 add_credit
Lines 758-775 and, if the syspref is set, renew them Link Here
758
sub _maybe_renew {
758
sub _maybe_renew {
759
    my ($items, $patron_id) = @_;
759
    my ($items, $patron_id) = @_;
760
760
761
    my $results = {
762
        ok     => [],
763
        not_ok => []
764
    };
765
761
    if (
766
    if (
762
        C4::Context->preference('RenewAccruingItemWhenPaid') &&
767
        C4::Context->preference('RenewAccruingItemWhenPaid') &&
763
        keys %{$items}
768
        keys %{$items}
764
    ) {
769
    ) {
770
        
765
        foreach my $itemnumber (keys %{$items}) {
771
        foreach my $itemnumber (keys %{$items}) {
766
            # Only do something if this item has no fines left on it
772
            # Only do something if this item has no fines left on it
767
            my $fine = C4::Overdues::GetFine( $itemnumber, $patron_id );
773
            my $fine = C4::Overdues::GetFine( $itemnumber, $patron_id );
768
            next if $fine && $fine > 0;
774
            next if $fine && $fine > 0;
769
775
770
            my ( $renew_ok, $error ) =
776
            my ( $can_renew, $error ) =
771
                C4::Circulation::CanBookBeRenewed($patron_id, $itemnumber);
777
                C4::Circulation::CanBookBeRenewed($patron_id, $itemnumber);
772
            if ( $renew_ok ) {
778
            if ( $can_renew ) {
773
                my $due_date = C4::Circulation::AddRenewal(
779
                my $due_date = C4::Circulation::AddRenewal(
774
                    $patron_id,
780
                    $patron_id,
775
                    $itemnumber,
781
                    $itemnumber,
Lines 778-789 sub _maybe_renew { Link Here
778
                    undef,
784
                    undef,
779
                    1
785
                    1
780
                );
786
                );
781
                return $due_date;
787
                push @{$results->{ok}}, {
788
                    itemnumber => $itemnumber,
789
                    due_date   => $due_date
790
                };
782
            } else {
791
            } else {
783
                return $error;
792
                push @{$results->{not_ok}}, {
793
                    itemnumber => $itemnumber,
794
                    error   => $error
795
                };
784
            }
796
            }
785
        }
797
        }
798
        return $results;
786
    }
799
    }
800
    return $results;
787
}
801
}
788
802
789
1;
803
1;
(-)a/Koha/REST/V1/Patrons/Account.pm (-1 / +1 lines)
Lines 132-138 sub add_credit { Link Here
132
        my $outstanding_credit = $credit->amountoutstanding;
132
        my $outstanding_credit = $credit->amountoutstanding;
133
        if ($debits) {
133
        if ($debits) {
134
            # pay them!
134
            # pay them!
135
            $outstanding_credit = $credit->apply({ debits => [ $debits->as_list ], offset_type => 'payment' });
135
            $outstanding_credit = $credit->apply({ debits => [ $debits->as_list ], offset_type => 'payment' })->{outstanding_amount};
136
        }
136
        }
137
137
138
        if ($outstanding_credit) {
138
        if ($outstanding_credit) {
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/renew_error_strings.inc (+30 lines)
Line 0 Link Here
1
[% SWITCH error %]
2
[% CASE 'no_item' %]
3
    No matching item could be found
4
[% CASE 'no_checkout' %]
5
    Item is not checked out
6
[% CASE 'too_soon' %]
7
    Cannot yet be renewed
8
[% CASE 'too_many' %]
9
    Renewed the maximum number of times
10
[% CASE 'auto_too_soon' %]
11
    Scheduled for automatic renewal and cannot yet be renewed
12
[% CASE 'auto_too_late' %]
13
    Scheduled for automatic renewal and cannot yet be any more
14
[% CASE 'auto_account_expired' %]
15
    Scheduled for automatic renewal and cannot be renewed because the patron's account has expired
16
[% CASE 'auto_renew' %]
17
    Scheduled for automatic renewal
18
[% CASE 'auto_too_much_oweing' %]
19
    Scheduled for automatic renewal
20
[% CASE 'on_reserve' %]
21
    On hold for another patron
22
[% CASE 'patron_restricted' %]
23
    Patron is currently restricted
24
[% CASE 'item_denied_renewal' %]
25
    Item is not allowed renewal
26
[% CASE 'onsite_checkout' %]
27
    Item is an onsite checkout
28
[% CASE %]
29
    Unknown error
30
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt (+8 lines)
Lines 39-44 Link Here
39
    <li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% patron.borrowernumber | uri %]" >Create manual credit</a></li>
39
    <li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% patron.borrowernumber | uri %]" >Create manual credit</a></li>
40
</ul>
40
</ul>
41
<div class="tabs-container">
41
<div class="tabs-container">
42
[% IF renew_errors.size > 0 %]
43
    <div class="alert">
44
        The fines on the following items were paid off, but the items could not be renewed:
45
        [% FOREACH problem IN renew_errors %]
46
            <p>[% INCLUDE 'biblio-title.inc' biblio=problem.item.biblio %] ( [% problem.item.barcode | html %] ): [% INCLUDE 'renew_error_strings.inc' error=problem.error %]</p>
47
        [% END %]
48
    </div>
49
[% END %]
42
<!-- The table with the account items -->
50
<!-- The table with the account items -->
43
<table id="table_account_fines">
51
<table id="table_account_fines">
44
    <thead>
52
    <thead>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt (+8 lines)
Lines 40-45 Link Here
40
    <form action="/cgi-bin/koha/members/pay.pl" method="post" id="pay-fines-form">
40
    <form action="/cgi-bin/koha/members/pay.pl" method="post" id="pay-fines-form">
41
    <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% patron.borrowernumber | html %]" />
41
    <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% patron.borrowernumber | html %]" />
42
<p><span class="checkall"><a id="CheckAll" href="#"><i class="fa fa-check"></i> Select all</a></span> | <span class="clearall"><a id="CheckNone" href="#"><i class="fa fa-remove"></i> Clear all</a></span></p>
42
<p><span class="checkall"><a id="CheckAll" href="#"><i class="fa fa-check"></i> Select all</a></span> | <span class="clearall"><a id="CheckNone" href="#"><i class="fa fa-remove"></i> Clear all</a></span></p>
43
[% IF renew_errors.size > 0 %]
44
    <div class="alert">
45
        The fines on the following items were paid off, but the items could not be renewed:
46
        [% FOREACH problem IN renew_errors %]
47
            <p>[% INCLUDE 'biblio-title.inc' biblio=problem.item.biblio %] ( [% problem.item.barcode | html %] ): [% INCLUDE 'renew_error_strings.inc' error=problem.error %]</p>
48
        [% END %]
49
    </div>
50
[% END %]
43
<table id="finest">
51
<table id="finest">
44
<thead>
52
<thead>
45
<tr>
53
<tr>
(-)a/members/boraccount.pl (+12 lines)
Lines 31-36 use C4::Members; Link Here
31
use C4::Accounts;
31
use C4::Accounts;
32
use Koha::Patrons;
32
use Koha::Patrons;
33
use Koha::Patron::Categories;
33
use Koha::Patron::Categories;
34
use Koha::Items;
34
35
35
my $input=new CGI;
36
my $input=new CGI;
36
37
Lines 51-56 my $borrowernumber = $input->param('borrowernumber'); Link Here
51
my $payment_id     = $input->param('payment_id');
52
my $payment_id     = $input->param('payment_id');
52
my $change_given   = $input->param('change_given');
53
my $change_given   = $input->param('change_given');
53
my $action         = $input->param('action') || '';
54
my $action         = $input->param('action') || '';
55
my @renew_errors   = $input->param('renew_error');
54
56
55
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
57
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
56
my $patron = Koha::Patrons->find( $borrowernumber );
58
my $patron = Koha::Patrons->find( $borrowernumber );
Lines 80-85 if($total <= 0){ Link Here
80
        $totalcredit = 1;
82
        $totalcredit = 1;
81
}
83
}
82
84
85
# Populate an arrayref with everything we need to display any
86
# renew errors that occurred based on what we were passed
87
my $renew_errors_display = [];  
88
foreach my $renew_error(@renew_errors) {
89
    my ($itemnumber, $error) = split(/,/, $renew_error);
90
    my $item = Koha::Items->find($itemnumber);
91
    push @{$renew_errors_display}, { item => $item, error => $error };
92
}
93
83
$template->param(
94
$template->param(
84
    patron              => $patron,
95
    patron              => $patron,
85
    finesview           => 1,
96
    finesview           => 1,
Lines 88-93 $template->param( Link Here
88
    accounts            => \@accountlines,
99
    accounts            => \@accountlines,
89
    payment_id          => $payment_id,
100
    payment_id          => $payment_id,
90
    change_given        => $change_given,
101
    change_given        => $change_given,
102
    renew_errors        => $renew_errors_display,
91
);
103
);
92
104
93
output_html_with_http_headers $input, $cookie, $template->output;
105
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/members/pay.pl (+12 lines)
Lines 39-44 use C4::Stats; Link Here
39
use C4::Koha;
39
use C4::Koha;
40
use C4::Overdues;
40
use C4::Overdues;
41
use Koha::Patrons;
41
use Koha::Patrons;
42
use Koha::Items;
42
43
43
use Koha::Patron::Categories;
44
use Koha::Patron::Categories;
44
use URI::Escape;
45
use URI::Escape;
Lines 65-70 if ( !$borrowernumber ) { Link Here
65
66
66
my $payment_id = $input->param('payment_id');
67
my $payment_id = $input->param('payment_id');
67
our $change_given = $input->param('change_given');
68
our $change_given = $input->param('change_given');
69
our @renew_errors = $input->param('renew_error');
68
70
69
# get borrower details
71
# get borrower details
70
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
72
my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in";
Lines 134-143 for (@names) { Link Here
134
    }
136
    }
135
}
137
}
136
138
139
# Populate an arrayref with everything we need to display any
140
# renew errors that occurred based on what we were passed
141
my $renew_errors_display = [];  
142
foreach my $renew_error(@renew_errors) {
143
    my ($itemnumber, $error) = split(/,/, $renew_error);
144
    my $item = Koha::Items->find($itemnumber);
145
    push @{$renew_errors_display}, { item => $item, error => $error };
146
}
147
137
$template->param(
148
$template->param(
138
    finesview  => 1,
149
    finesview  => 1,
139
    payment_id => $payment_id,
150
    payment_id => $payment_id,
140
    change_given => $change_given,
151
    change_given => $change_given,
152
    renew_errors => $renew_errors_display
141
);
153
);
142
154
143
add_accounts_to_template();
155
add_accounts_to_template();
(-)a/members/paycollect.pl (-6 / +23 lines)
Lines 151-157 if ( $total_paid and $total_paid ne '0.00' ) { Link Here
151
151
152
        if ($pay_individual) {
152
        if ($pay_individual) {
153
            my $line = Koha::Account::Lines->find($accountlines_id);
153
            my $line = Koha::Account::Lines->find($accountlines_id);
154
            $payment_id = $account->pay(
154
            my $pay_result = $account->pay(
155
                {
155
                {
156
                    lines        => [$line],
156
                    lines        => [$line],
157
                    amount       => $total_paid,
157
                    amount       => $total_paid,
Lines 162-170 if ( $total_paid and $total_paid ne '0.00' ) { Link Here
162
                    cash_register => $registerid
162
                    cash_register => $registerid
163
                }
163
                }
164
            );
164
            );
165
            $payment_id = $pay_result->{payment_id};
166
            # It's possible renewals took place, parse any renew results
167
            # and pass errors on
168
            my @renew_errors = map { "renew_error=$_->{itemnumber},$_->{error}" }
169
                @{$pay_result->{renew_result}->{not_ok}};
170
            my $renew_result = $pay_result->{renew_result};
171
            my $append = scalar @renew_errors ? '&' . join('&', @renew_errors) : '';
172
165
            print $input->redirect(
173
            print $input->redirect(
166
                "/cgi-bin/koha/members/pay.pl?borrowernumber=$borrowernumber&payment_id=$payment_id&change_given=$change_given");
174
                "/cgi-bin/koha/members/pay.pl?borrowernumber=$borrowernumber&payment_id=$payment_id&change_given=${change_given}${append}");
167
        } else {
175
        } else {
176
            my $pay_result;
168
            if ($select) {
177
            if ($select) {
169
                if ( $select =~ /^([\d,]*).*/ ) {
178
                if ( $select =~ /^([\d,]*).*/ ) {
170
                    $select = $1;    # ensure passing no junk
179
                    $select = $1;    # ensure passing no junk
Lines 181-187 if ( $total_paid and $total_paid ne '0.00' ) { Link Here
181
                    { order_by => 'date' }
190
                    { order_by => 'date' }
182
                );
191
                );
183
192
184
                $payment_id = $account->pay(
193
                $pay_result = $account->pay(
185
                    {
194
                    {
186
                        type         => $type,
195
                        type         => $type,
187
                        amount       => $total_paid,
196
                        amount       => $total_paid,
Lines 193-202 if ( $total_paid and $total_paid ne '0.00' ) { Link Here
193
                        cash_register => $registerid
202
                        cash_register => $registerid
194
                    }
203
                    }
195
                  );
204
                  );
205
                  $payment_id = $pay_result->{payment_id};
196
            }
206
            }
197
            else {
207
            else {
198
                my $note = $input->param('selected_accts_notes');
208
                my $note = $input->param('selected_accts_notes');
199
                $payment_id = $account->pay(
209
                $pay_result = $payment_id = $account->pay(
200
                    {
210
                    {
201
                        amount       => $total_paid,
211
                        amount       => $total_paid,
202
                        library_id   => $library_id,
212
                        library_id   => $library_id,
Lines 208-215 if ( $total_paid and $total_paid ne '0.00' ) { Link Here
208
                    }
218
                    }
209
                );
219
                );
210
            }
220
            }
211
221
            $payment_id = $pay_result->{payment_id};
212
            print $input->redirect("/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber&payment_id=$payment_id&change_given=$change_given");
222
            # It's possible renewals took place, parse any renew results
223
            # and pass errors on
224
            my @renew_errors = map { "renew_error=$_->{itemnumber},$_->{error}" }
225
                @{$pay_result->{renew_result}->{not_ok}};
226
            my $renew_result = $pay_result->{renew_result};
227
            my $append = scalar @renew_errors ? '&' . join('&', @renew_errors) : '';
228
229
            print $input->redirect("/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber&payment_id=$payment_id&change_given=${change_given}${append}");
213
        }
230
        }
214
    }
231
    }
215
} else {
232
} else {
(-)a/t/db_dependent/Accounts.t (-8 / +8 lines)
Lines 203-209 subtest "Koha::Account::pay tests" => sub { Link Here
203
    my $borrowernumber = $borrower->borrowernumber;
203
    my $borrowernumber = $borrower->borrowernumber;
204
    my $data = '20.00';
204
    my $data = '20.00';
205
    my $payment_note = '$20.00 payment note';
205
    my $payment_note = '$20.00 payment note';
206
    my $id = $account->pay( { amount => $data, note => $payment_note, payment_type => "TEST_TYPE" } );
206
    my $id = $account->pay( { amount => $data, note => $payment_note, payment_type => "TEST_TYPE" } )->{payment_id};
207
207
208
    my $accountline = Koha::Account::Lines->find( $id );
208
    my $accountline = Koha::Account::Lines->find( $id );
209
    is( $accountline->payment_type, "TEST_TYPE", "Payment type passed into pay is set in account line correctly" );
209
    is( $accountline->payment_type, "TEST_TYPE", "Payment type passed into pay is set in account line correctly" );
Lines 283-289 subtest "Koha::Account::pay tests" => sub { Link Here
283
    is($note,'$200.00 payment note', '$200.00 payment note is registered');
283
    is($note,'$200.00 payment note', '$200.00 payment note is registered');
284
284
285
    my $line3 = $account->add_debit({ type => 'account', amount => 42, interface => 'commandline' });
285
    my $line3 = $account->add_debit({ type => 'account', amount => 42, interface => 'commandline' });
286
    my $payment_id = $account->pay( { lines => [$line3], amount => 42 } );
286
    my $payment_id = $account->pay( { lines => [$line3], amount => 42 } )->{payment_id};
287
    my $payment = Koha::Account::Lines->find( $payment_id );
287
    my $payment = Koha::Account::Lines->find( $payment_id );
288
    is( $payment->amount(), '-42.000000', "Payment paid the specified fine" );
288
    is( $payment->amount(), '-42.000000', "Payment paid the specified fine" );
289
    $line3 = Koha::Account::Lines->find( $line3->id );
289
    $line3 = Koha::Account::Lines->find( $line3->id );
Lines 365-371 subtest "Koha::Account::pay writeoff tests" => sub { Link Here
365
            amount => 42,
365
            amount => 42,
366
            type   => 'writeoff',
366
            type   => 'writeoff',
367
        }
367
        }
368
    );
368
    )->{payment_id};
369
369
370
    $line->_result->discard_changes();
370
    $line->_result->discard_changes();
371
371
Lines 1001-1007 subtest "Koha::Account::Offset credit & debit tests" => sub { Link Here
1001
            lines  => [$line1, $line2],
1001
            lines  => [$line1, $line2],
1002
            amount => 30,
1002
            amount => 30,
1003
        }
1003
        }
1004
    );
1004
    )->{payment_id};
1005
1005
1006
    # Test debit and credit methods for Koha::Account::Offset
1006
    # Test debit and credit methods for Koha::Account::Offset
1007
    my $account_offset = Koha::Account::Offsets->find( { credit_id => $id, debit_id => $line1->id } );
1007
    my $account_offset = Koha::Account::Offsets->find( { credit_id => $id, debit_id => $line1->id } );
Lines 1060-1074 subtest "Payment notice tests" => sub { Link Here
1060
    $letter->store();
1060
    $letter->store();
1061
1061
1062
    t::lib::Mocks::mock_preference('UseEmailReceipts', '0');
1062
    t::lib::Mocks::mock_preference('UseEmailReceipts', '0');
1063
    my $id = $account->pay( { amount => 1 } );
1063
    my $id = $account->pay( { amount => 1 } )->{payment_id};
1064
    is( Koha::Notice::Messages->search()->count(), 0, 'Notice for payment not sent if UseEmailReceipts is disabled' );
1064
    is( Koha::Notice::Messages->search()->count(), 0, 'Notice for payment not sent if UseEmailReceipts is disabled' );
1065
1065
1066
    $id = $account->pay( { amount => 1, type => 'writeoff' } );
1066
    $id = $account->pay( { amount => 1, type => 'writeoff' } )->{payment_id};
1067
    is( Koha::Notice::Messages->search()->count(), 0, 'Notice for writeoff not sent if UseEmailReceipts is disabled' );
1067
    is( Koha::Notice::Messages->search()->count(), 0, 'Notice for writeoff not sent if UseEmailReceipts is disabled' );
1068
1068
1069
    t::lib::Mocks::mock_preference('UseEmailReceipts', '1');
1069
    t::lib::Mocks::mock_preference('UseEmailReceipts', '1');
1070
1070
1071
    $id = $account->pay( { amount => 12 } );
1071
    $id = $account->pay( { amount => 12 } )->{payment_id};
1072
    my $notice = Koha::Notice::Messages->search()->next();
1072
    my $notice = Koha::Notice::Messages->search()->next();
1073
    is( $notice->subject, 'Account payment', 'Notice subject is correct for payment' );
1073
    is( $notice->subject, 'Account payment', 'Notice subject is correct for payment' );
1074
    is( $notice->letter_code, 'ACCOUNT_PAYMENT', 'Notice letter code is correct for payment' );
1074
    is( $notice->letter_code, 'ACCOUNT_PAYMENT', 'Notice letter code is correct for payment' );
Lines 1079-1085 subtest "Payment notice tests" => sub { Link Here
1079
    $letter->content('[%- USE Price -%]A writeoff of [% credit.amount * -1 | $Price %] has been applied to your account.');
1079
    $letter->content('[%- USE Price -%]A writeoff of [% credit.amount * -1 | $Price %] has been applied to your account.');
1080
    $letter->store();
1080
    $letter->store();
1081
1081
1082
    $id = $account->pay( { amount => 13, type => 'writeoff' } );
1082
    $id = $account->pay( { amount => 13, type => 'writeoff' } )->{payment_id};
1083
    $notice = Koha::Notice::Messages->search()->next();
1083
    $notice = Koha::Notice::Messages->search()->next();
1084
    is( $notice->subject, 'Account writeoff', 'Notice subject is correct for payment' );
1084
    is( $notice->subject, 'Account writeoff', 'Notice subject is correct for payment' );
1085
    is( $notice->letter_code, 'ACCOUNT_WRITEOFF', 'Notice letter code is correct for writeoff' );
1085
    is( $notice->letter_code, 'ACCOUNT_WRITEOFF', 'Notice letter code is correct for writeoff' );
(-)a/t/db_dependent/Koha/Account.t (-2 / +2 lines)
Lines 597-608 subtest 'pay() tests' => sub { Link Here
597
    my $context = Test::MockModule->new('C4::Context');
597
    my $context = Test::MockModule->new('C4::Context');
598
    $context->mock( 'userenv', { branch => $library->id } );
598
    $context->mock( 'userenv', { branch => $library->id } );
599
599
600
    my $credit_1_id = $account->pay({ amount => 200 });
600
    my $credit_1_id = $account->pay({ amount => 200 })->{payment_id};
601
    my $credit_1    = Koha::Account::Lines->find( $credit_1_id );
601
    my $credit_1    = Koha::Account::Lines->find( $credit_1_id );
602
602
603
    is( $credit_1->branchcode, undef, 'No branchcode is set if library_id was not passed' );
603
    is( $credit_1->branchcode, undef, 'No branchcode is set if library_id was not passed' );
604
604
605
    my $credit_2_id = $account->pay({ amount => 150, library_id => $library->id });
605
    my $credit_2_id = $account->pay({ amount => 150, library_id => $library->id })->{payment_id};
606
    my $credit_2    = Koha::Account::Lines->find( $credit_2_id );
606
    my $credit_2    = Koha::Account::Lines->find( $credit_2_id );
607
607
608
    is( $credit_2->branchcode, $library->id, 'branchcode set because library_id was passed' );
608
    is( $credit_2->branchcode, $library->id, 'branchcode set because library_id was passed' );
(-)a/t/db_dependent/Koha/Account/Lines.t (-2 / +1 lines)
Lines 601-607 subtest "void() tests" => sub { Link Here
601
            lines  => [$line1, $line2],
601
            lines  => [$line1, $line2],
602
            amount => 30,
602
            amount => 30,
603
        }
603
        }
604
    );
604
    )->{payment_id};
605
605
606
    my $account_payment = Koha::Account::Lines->find( $id );
606
    my $account_payment = Koha::Account::Lines->find( $id );
607
607
608
- 

Return to bug 23051